config-easy 0.2.1

A small interactive settings menu for command-line Rust applications
Documentation
use std::cell::RefCell;

use config_easy::{SettingRow, SettingsQuery, SettingsStore};

struct AppSettings {
    rows: RefCell<Vec<SettingRow>>,
}

impl AppSettings {
    fn new() -> Self {
        Self {
            rows: RefCell::new(vec![
                SettingRow {
                    key: "log_level".to_string(),
                    value: "info".to_string(),
                },
                SettingRow {
                    key: "api_token".to_string(),
                    value: "secret-token".to_string(),
                },
            ]),
        }
    }
}

impl SettingsStore for AppSettings {
    fn load_settings(
        &self,
        _query: &SettingsQuery<'_>,
    ) -> Result<Vec<SettingRow>, Box<dyn std::error::Error + Send + Sync>> {
        Ok(self.rows.borrow().clone())
    }

    fn update_setting(
        &self,
        _query: &SettingsQuery<'_>,
        key: &str,
        value: &str,
    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        if let Some(row) = self.rows.borrow_mut().iter_mut().find(|row| row.key == key) {
            row.value = value.to_string();
        }

        Ok(())
    }
}

fn main() {
    let store = AppSettings::new();

    let _ = config_easy::builder(store)
        .secret_keys(["api_token"])
        .validator(|key, value| {
            if key == "log_level" && !["debug", "info", "warn", "error"].contains(&value) {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::InvalidInput,
                    "expected one of debug, info, warn, error",
                )
                .into());
            }

            Ok(())
        })
        .action("reset", "reset settings", || {
            println!("Reset settings here.");
            Ok(())
        })
        .run();
}