use std::path::PathBuf;
use anyhow::{Result, Context};
use std::fs;
use crate::config::settings::Settings;
use crate::config::structs::PartialConfig;
pub fn config_dir() -> Option<PathBuf> {
dirs::config_dir().map(|p| p.join("eazygit"))
}
pub fn load() -> Result<Settings> {
let mut settings = Settings::default();
if let Some(config_dir) = config_dir() {
let global_config = config_dir.join("config.toml");
if global_config.exists() {
let content = fs::read_to_string(&global_config)
.context(format!("Failed to read config at {:?}", global_config))?;
let partial: PartialConfig = toml::from_str(&content)
.context("Failed to parse global config")?;
apply_partial(&mut settings, partial);
}
}
let local_config = PathBuf::from("eazygit.toml");
if local_config.exists() {
let content = fs::read_to_string(&local_config)
.context("Failed to read local eazygit.toml")?;
let partial: PartialConfig = toml::from_str(&content)
.context("Failed to parse local config")?;
apply_partial(&mut settings, partial);
}
Ok(settings)
}
pub fn persist_theme(theme_name: &str) -> Result<()> {
if let Some(config_dir) = config_dir() {
if !config_dir.exists() {
fs::create_dir_all(&config_dir)?;
}
let config_path = config_dir.join("config.toml");
let mut content = if config_path.exists() {
fs::read_to_string(&config_path)?
} else {
String::new()
};
if content.contains("[ui]") {
if content.contains("theme =") {
let lines: Vec<&str> = content.lines().collect();
let mut new_lines = Vec::new();
let mut in_ui = false;
for line in lines {
if line.trim() == "[ui]" {
in_ui = true;
new_lines.push(line.to_string());
} else if line.trim().starts_with("[") {
in_ui = false;
new_lines.push(line.to_string());
} else if in_ui && line.trim().starts_with("theme") {
new_lines.push(format!("theme = \"{}\"", theme_name));
} else {
new_lines.push(line.to_string());
}
}
content = new_lines.join("\n");
} else {
content = content.replace("[ui]", &format!("[ui]\ntheme = \"{}\"", theme_name));
}
} else {
content.push_str(&format!("\n[ui]\ntheme = \"{}\"\n", theme_name));
}
fs::write(config_path, content)?;
}
Ok(())
}
fn apply_partial(cfg: &mut Settings, partial: PartialConfig) {
if let Some(p) = partial.core {
if let Some(v) = p.editor { cfg.core.editor = Some(v); }
if let Some(v) = p.auto_fetch { cfg.core.auto_fetch = v; }
if let Some(v) = p.auto_fetch_interval { cfg.core.auto_fetch_interval = v; }
if let Some(v) = p.auto_fetch_remote { cfg.core.auto_fetch_remote = v; }
if let Some(v) = p.format_command { cfg.core.format_command = Some(v); }
if let Some(v) = p.format_on_revert { cfg.core.format_on_revert = v; }
if let Some(v) = p.push_ff_only_enforce { cfg.core.push_ff_only_enforce = v; }
if let Some(v) = p.pull_ff_only { cfg.core.pull_ff_only = v; }
if let Some(v) = p.pull_autostash { cfg.core.pull_autostash = v; }
if let Some(v) = p.pull_timeout_secs { cfg.core.pull_timeout_secs = v; }
if let Some(v) = p.rebase_timeout_secs { cfg.core.rebase_timeout_secs = v; }
}
if let Some(p) = partial.diff {
if let Some(v) = p.context_lines { cfg.diff.context_lines = v; }
if let Some(v) = p.syntax_highlight { cfg.diff.syntax_highlight = v; }
}
if let Some(p) = partial.ui {
if let Some(v) = p.theme { cfg.ui.theme = v; }
if let Some(v) = p.show_help_footer { cfg.ui.show_help_footer = v; }
if let Some(v) = p.font_family { cfg.ui.font_family = Some(v); }
if let Some(v) = p.font_size { cfg.ui.font_size = Some(v); }
}
if let Some(pt) = partial.theme {
crate::config::theme::loader::merge_partial(&mut cfg.theme, pt);
}
let legacy_partial = crate::config::theme::PartialThemeConfig {
fg: partial.fg, bg: partial.bg, muted: partial.muted, accent: partial.accent,
border: partial.border, border_focused: partial.border_focused,
selection_bg: partial.selection_bg, selection_fg: partial.selection_fg,
diff_add: partial.diff_add, diff_remove: partial.diff_remove,
diff_context: partial.diff_context, diff_hunk: partial.diff_hunk,
staged: partial.staged, unstaged: partial.unstaged, untracked: partial.untracked,
header: partial.header, footer: partial.footer,
error: partial.error, warning: partial.warning, success: partial.success,
};
crate::config::theme::loader::merge_partial(&mut cfg.theme, legacy_partial);
if let Some(k) = partial.keymap {
cfg.keymap.extend(k);
}
if let Some(c) = partial.commands {
cfg.custom_commands.extend(c);
}
}
pub fn create_default_config() -> Result<()> {
if let Some(config_dir) = config_dir() {
if !config_dir.exists() {
fs::create_dir_all(&config_dir)?;
}
let config_path = config_dir.join("config.toml");
if !config_path.exists() {
let default_content = r##"
# EazyGit Configuration
[core]
# editor = "vim"
auto_fetch = true
auto_fetch_interval = 60 # seconds
[ui]
theme = "default_dark"
# show_help_footer = true
[keymap]
# "shift-p" = "push"
[theme]
# Override specific colors here
# accent = "#ff00ff"
"##;
fs::write(config_path, default_content.trim())?;
}
}
Ok(())
}