iforgor 0.3.3

The CLI tool for all those commands you forget about
Documentation
use {
    serde::{Deserialize, Serialize},
    std::collections::BTreeMap,
};

use crate::on_disk::OnDisk;

const ARG_HISTORY_FILE: &str = ".arg_history.toml";

/// Persisted argument values keyed by "{command_id}/{arg_name}".
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ArgHistory {
    pub entries: BTreeMap<String, String>,
}

impl ArgHistory {
    fn make_key(command_id: &str, arg_name: &str) -> String {
        format!("{command_id}/{arg_name}")
    }

    /// Get the last used value for a command's argument.
    pub fn get(&self, command_id: &str, arg_name: &str) -> Option<&str> {
        self.entries
            .get(&Self::make_key(command_id, arg_name))
            .map(|s| s.as_str())
    }

    /// Set the last used value for a command's argument.
    pub fn set(&mut self, command_id: &str, arg_name: &str, value: &str) {
        self.entries
            .insert(Self::make_key(command_id, arg_name), value.to_string());
    }

    /// Load from the app data directory (~/.iforgor/).
    pub fn load(app_dir: &std::path::Path) -> OnDisk<Self> {
        let path = app_dir.join(ARG_HISTORY_FILE);
        OnDisk::<Self>::open_or_default(path.clone())
            .unwrap_or_else(|_| OnDisk::new_from_default(path))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn get_set_roundtrip() {
        let mut h = ArgHistory::default();
        h.set("cmd1", "BRANCH", "main");
        assert_eq!(h.get("cmd1", "BRANCH"), Some("main"));
    }

    #[test]
    fn get_missing() {
        let h = ArgHistory::default();
        assert_eq!(h.get("cmd1", "BRANCH"), None);
    }

    #[test]
    fn set_overwrites() {
        let mut h = ArgHistory::default();
        h.set("cmd1", "BRANCH", "main");
        h.set("cmd1", "BRANCH", "develop");
        assert_eq!(h.get("cmd1", "BRANCH"), Some("develop"));
    }

    #[test]
    fn different_commands_different_keys() {
        let mut h = ArgHistory::default();
        h.set("cmd1", "BRANCH", "main");
        h.set("cmd2", "BRANCH", "develop");
        assert_eq!(h.get("cmd1", "BRANCH"), Some("main"));
        assert_eq!(h.get("cmd2", "BRANCH"), Some("develop"));
    }
}