Skip to main content

dkdc_rs/
config.rs

1use anyhow::{Context, Result};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use std::fs;
5use std::path::PathBuf;
6
7#[derive(Debug, Serialize, Deserialize, Default)]
8pub struct Config {
9    #[serde(default)]
10    pub aliases: HashMap<String, String>,
11    #[serde(default)]
12    pub things: HashMap<String, String>,
13}
14
15const DEFAULT_CONFIG: &str = r#"# dkdc config file
16[aliases]
17a = "thing"
18alias = "thing"
19[things]
20thing = "https://github.com/lostmygithubaccount/dkdc"
21"#;
22
23pub fn config_path() -> Result<PathBuf> {
24    let home_dir = dirs::home_dir().context("Failed to get home directory")?;
25    Ok(home_dir.join(".dkdc").join("config.toml"))
26}
27
28pub fn init_config() -> Result<()> {
29    let config_path = config_path()?;
30    let config_dir = config_path.parent().unwrap();
31
32    fs::create_dir_all(config_dir).context("Failed to create config directory")?;
33
34    if !config_path.exists() {
35        fs::write(&config_path, DEFAULT_CONFIG).context("Failed to write default config")?;
36    }
37
38    Ok(())
39}
40
41pub fn load_config() -> Result<Config> {
42    let config_path = config_path()?;
43    let contents = fs::read_to_string(&config_path).context("Failed to read config file")?;
44    let config: Config = toml::from_str(&contents).context("Failed to parse config file")?;
45    Ok(config)
46}
47
48pub fn config_it() -> Result<()> {
49    let config_path = config_path()?;
50    let editor = std::env::var("EDITOR").unwrap_or_else(|_| "vi".to_string());
51
52    println!("opening {} with {}...", config_path.display(), editor);
53
54    let status = std::process::Command::new(&editor)
55        .arg(&config_path)
56        .status()
57        .with_context(|| format!("editor {} not found in PATH", editor))?;
58
59    if !status.success() {
60        anyhow::bail!("Editor exited with non-zero status");
61    }
62
63    Ok(())
64}
65
66pub fn print_config(config: &Config) -> Result<()> {
67    let sections = vec![("aliases", &config.aliases), ("things", &config.things)];
68
69    for (section_name, section_data) in sections {
70        if section_data.is_empty() {
71            continue;
72        }
73
74        println!("{}:", section_name);
75        println!();
76
77        let mut keys: Vec<_> = section_data.keys().collect();
78        keys.sort();
79
80        let max_key_len = keys.iter().map(|k| k.len()).max().unwrap_or(0);
81
82        for key in keys {
83            if let Some(value) = section_data.get(key) {
84                println!("• {:<width$} | {}", key, value, width = max_key_len);
85            }
86        }
87
88        println!();
89    }
90
91    Ok(())
92}