herdr-pretty-which 0.1.5

A tasteful which-key style command palette for Herdr
Documentation
use crate::model::KeysSection;
use crate::theme::ThemeConfig;
use anyhow::{Context, Result};
use serde::Deserialize;
use std::fs;
use std::path::{Path, PathBuf};

#[derive(Debug, Clone, Deserialize, Default)]
pub struct HerdrConfig {
    #[serde(default)]
    pub keys: KeysSection,
    #[serde(default)]
    pub theme: ThemeConfig,
}

#[derive(Debug, Clone)]
pub struct HerdrConfigSource {
    pub path: PathBuf,
    pub config: HerdrConfig,
}

pub fn load_herdr_config(explicit_path: Option<PathBuf>) -> Result<HerdrConfigSource> {
    let path = explicit_path
        .or_else(|| std::env::var_os("HERDR_CONFIG_PATH").map(PathBuf::from))
        .or_else(default_config_path)
        .context("could not resolve Herdr config path")?;
    load_herdr_config_from_path(path)
}

pub fn load_herdr_config_from_path(path: impl AsRef<Path>) -> Result<HerdrConfigSource> {
    let path = path.as_ref().to_path_buf();
    let text =
        fs::read_to_string(&path).with_context(|| format!("failed to read {}", path.display()))?;
    let config = toml::from_str::<HerdrConfig>(&text)
        .with_context(|| format!("failed to parse {}", path.display()))?;
    Ok(HerdrConfigSource { path, config })
}

fn default_config_path() -> Option<PathBuf> {
    dirs::home_dir().map(|home| home.join(".config").join("herdr").join("config.toml"))
}

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

    #[test]
    fn parses_config_with_custom_key() {
        let dir = tempfile::tempdir().unwrap();
        let path = dir.path().join("config.toml");
        fs::write(
            &path,
            "[keys]\nnext_tab = [\"prefix+n\", \"ctrl+alt+n\"]\n[theme]\nname = \"terminal\"\n",
        )
        .unwrap();
        let source = load_herdr_config_from_path(&path).unwrap();
        let bindings = crate::model::effective_bindings(&source.config.keys);
        let next = bindings
            .iter()
            .find(|binding| binding.action == "next_tab")
            .unwrap();
        assert_eq!(next.source, BindingSource::Custom);
        assert_eq!(next.keys, vec!["prefix+n", "ctrl+alt+n"]);
    }
}