use std::fs;
use std::path::Path;
use log::warn;
use crate::config::paths::{UblxPaths, normalize_rel_path_for_policy};
use crate::config::theme::auto_correct_theme_name;
use super::{EnhancePolicy, EnhancePolicyEntry, LayoutOverlay, UblxOverlay};
fn ensure_parent_dir(path: &Path, what: &str) -> bool {
let Some(parent) = path.parent() else {
return true;
};
if let Err(e) = fs::create_dir_all(parent) {
warn!("could not create {what} {}: {}", parent.display(), e);
return false;
}
true
}
#[must_use]
pub fn default_overlay_for_new_file(default_theme_display_name: &str) -> UblxOverlay {
UblxOverlay {
show_hidden_files: Some(false),
hash: Some(false),
theme: Some(default_theme_display_name.to_string()),
layout: Some(LayoutOverlay::default()),
enable_enhance_all: Some(false),
ask_enhance_on_new_root: Some(true),
run_snapshot_on_startup: Some(true),
..Default::default()
}
}
pub fn ensure_global_config_file_with_defaults(
global_path: &Path,
default_theme_display_name: &str,
) {
if global_path.exists() {
return;
}
if !ensure_parent_dir(global_path, "global config parent") {
return;
}
let overlay = default_overlay_for_new_file(default_theme_display_name);
match toml::to_string_pretty(&overlay) {
Ok(s) => {
if let Err(e) = fs::write(global_path, s) {
warn!(
"could not write default global config {}: {}",
global_path.display(),
e
);
}
}
Err(e) => warn!("could not serialize default global overlay: {e}"),
}
}
pub fn ensure_local_config_file_with_defaults(paths: &UblxPaths, default_theme_display_name: &str) {
let path = paths.toml_path().unwrap_or_else(|| paths.hidden_toml());
if path.exists() {
return;
}
if !ensure_parent_dir(&path, "local config parent") {
return;
}
let overlay = default_overlay_for_new_file(default_theme_display_name);
match toml::to_string_pretty(&overlay) {
Ok(s) => {
if let Err(e) = fs::write(&path, s) {
warn!(
"could not write default local config {}: {}",
path.display(),
e
);
}
}
Err(e) => warn!("could not serialize default local overlay: {e}"),
}
}
#[must_use]
pub fn load_ublx_toml(
path: Option<std::path::PathBuf>,
valid_theme_names: Option<&[&str]>,
) -> Option<UblxOverlay> {
let path = path?;
let s = fs::read_to_string(&path).ok()?;
match toml::from_str::<UblxOverlay>(&s) {
Ok(mut overlay) => {
let corrected_theme =
valid_theme_names
.zip(overlay.theme.as_deref())
.and_then(|(valid, theme)| {
auto_correct_theme_name(theme, valid)
.filter(|corrected| *corrected != theme)
});
if let Some(corrected) = corrected_theme {
overlay.theme = Some(corrected.to_string());
write_corrected_overlay(&path, &overlay);
}
Some(overlay)
}
Err(e) => {
warn!("{}: parse error, ignoring: {}", path.display(), e);
None
}
}
}
pub fn write_ublx_overlay_at(path: &Path, overlay: &UblxOverlay) {
match toml::to_string_pretty(overlay) {
Ok(s) => {
if let Err(e) = fs::write(path, s) {
warn!("could not write {}: {}", path.display(), e);
}
}
Err(e) => warn!("could not serialize overlay for {}: {}", path.display(), e),
}
}
pub fn write_corrected_overlay(path: &Path, overlay: &UblxOverlay) {
match toml::to_string_pretty(overlay) {
Ok(updated) => {
if let Err(e) = fs::write(path, updated) {
warn!(
"could not write corrected theme to {}: {}",
path.display(),
e
);
}
}
Err(e) => warn!(
"could not serialize corrected overlay {}: {}",
path.display(),
e
),
}
}
pub fn save_overlay_to_cache(ublx_paths: &UblxPaths, overlay: &UblxOverlay) {
let Some(path) = ublx_paths.last_applied_config_path() else {
return;
};
if !ensure_parent_dir(&path, "cache dir") {
return;
}
match toml::to_string_pretty(overlay) {
Ok(s) => {
if let Err(e) = fs::write(&path, s) {
warn!("could not write cache config {}: {}", path.display(), e);
}
}
Err(e) => warn!("could not serialize overlay for cache: {e}"),
}
}
pub fn write_local_theme(paths: &UblxPaths, theme_display_name: &str) {
let path = paths.toml_path().unwrap_or_else(|| paths.hidden_toml());
let mut overlay = load_ublx_toml(Some(path.clone()), None).unwrap_or_default();
overlay.theme = Some(theme_display_name.to_string());
if !ensure_parent_dir(&path, "config dir") {
return;
}
match toml::to_string_pretty(&overlay) {
Ok(s) => {
if let Err(e) = fs::write(&path, s) {
warn!("could not write theme to {}: {}", path.display(), e);
}
}
Err(e) => warn!("could not serialize overlay: {e}"),
}
}
pub fn write_local_enhance_only_toml(
ublx_paths: &UblxPaths,
enable_enhance_all: bool,
) -> std::io::Result<()> {
let overlay = UblxOverlay {
enable_enhance_all: Some(enable_enhance_all),
..Default::default()
};
let s = toml::to_string(&overlay).map_err(std::io::Error::other)?;
let path = ublx_paths.hidden_toml();
if !ensure_parent_dir(&path, "config dir") {
return Err(std::io::Error::other(
"could not create parent directory for local config",
));
}
fs::write(path, s)
}
pub fn write_local_enhance_policy(paths: &UblxPaths, rel_path: &str, policy: EnhancePolicy) {
let path = paths.toml_path().unwrap_or_else(|| paths.hidden_toml());
let mut overlay = load_ublx_toml(Some(path.clone()), None).unwrap_or_default();
let mut entries = overlay.enhance_policy.unwrap_or_default();
let norm = normalize_rel_path_for_policy(rel_path);
entries.retain(|e| normalize_rel_path_for_policy(&e.path) != norm);
entries.push(EnhancePolicyEntry { path: norm, policy });
overlay.enhance_policy = Some(entries);
if !ensure_parent_dir(&path, "config dir") {
return;
}
match toml::to_string_pretty(&overlay) {
Ok(s) => {
if let Err(e) = fs::write(&path, s) {
warn!(
"could not write enhance_policy to {}: {}",
path.display(),
e
);
}
}
Err(e) => warn!("could not serialize overlay: {e}"),
}
}