tmuxship 0.1.3

A Starship-to-tmux adapter that renders tmux-ready status lines from Starship JSON output
Documentation
use anyhow::{anyhow, Result};
use serde::Serialize;
use shellexpand::tilde;
use std::collections::HashMap;
use std::path::{Path, PathBuf};

#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)]
pub enum Side {
    Left,
    Right,
    Full,
    Center,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ConfigResolution {
    pub side: Side,
    pub config_path: PathBuf,
    pub source: String,
}

impl ConfigResolution {
    fn new(side: Side, path: PathBuf, source: impl Into<String>) -> Self {
        Self {
            side,
            config_path: path,
            source: source.into(),
        }
    }
}

fn expand_user(path: &Path) -> PathBuf {
    let as_str = path.to_string_lossy();
    let expanded = tilde(&as_str);
    PathBuf::from(expanded.as_ref())
}

fn ensure_file(path: PathBuf, context: &str) -> Result<PathBuf> {
    if path.is_file() {
        Ok(path)
    } else {
        Err(anyhow!("{}: {}", context, path.display()))
    }
}

pub fn resolve_config(
    side: Side,
    override_path: Option<PathBuf>,
    env: &HashMap<String, String>,
) -> Result<ConfigResolution> {
    let normalized_side = match side {
        Side::Left => "LEFT",
        Side::Right => "RIGHT",
        Side::Full => "FULL",
        Side::Center => "CENTER",
    };

    if let Some(path) = override_path {
        let expanded = ensure_file(expand_user(&path), "Config override does not exist")?;
        return Ok(ConfigResolution::new(side, expanded, "override"));
    }

    let side_env_var = format!("TMUX_SHIP_{}_CONFIG", normalized_side);
    if let Some(value) = env.get(&side_env_var) {
        let expanded = ensure_file(
            expand_user(Path::new(value)),
            "Environment-specified config does not exist",
        )?;
        return Ok(ConfigResolution::new(side, expanded, side_env_var));
    }

    if let Some(value) = env.get("STARSHIP_CONFIG") {
        let expanded = ensure_file(
            expand_user(Path::new(value)),
            "STARSHIP_CONFIG points to missing file",
        )?;
        return Ok(ConfigResolution::new(side, expanded, "STARSHIP_CONFIG"));
    }

    let mut candidate_dirs: Vec<(PathBuf, &str)> = Vec::new();
    if let Some(xdg_config) = env.get("XDG_CONFIG_HOME") {
        let xdg = expand_user(Path::new(xdg_config));
        candidate_dirs.push((xdg.join("tmux"), "tmux"));
        candidate_dirs.push((xdg.join("starship"), "starship"));
    }
    if let Some(home) = env.get("HOME") {
        let home = expand_user(Path::new(home));
        candidate_dirs.push((home.join(".config/tmux"), "tmux"));
        candidate_dirs.push((home.join(".tmux"), "tmux"));
        candidate_dirs.push((home.join(".config/starship"), "starship"));
    } else if let Some(home_dir) = dirs::home_dir() {
        candidate_dirs.push((home_dir.join(".config/tmux"), "tmux"));
        candidate_dirs.push((home_dir.join(".tmux"), "tmux"));
        candidate_dirs.push((home_dir.join(".config/starship"), "starship"));
    }

    let side_filename = match side {
        Side::Left => ".left.toml",
        Side::Right => ".right.toml",
        Side::Full => ".full.toml",
        Side::Center => ".center.toml",
    };

    for (base, kind) in candidate_dirs {
        if !base.exists() {
            continue;
        }
        let side_path = base.join(side_filename);
        if side_path.is_file() {
            let source = if kind == "tmux" {
                "tmux-side"
            } else {
                "default-side"
            };
            return Ok(ConfigResolution::new(side, side_path, source));
        }
        let global_path = base.join("starship.toml");
        if global_path.is_file() {
            let source = if kind == "tmux" {
                "tmux-global"
            } else {
                "default-global"
            };
            return Ok(ConfigResolution::new(side, global_path, source));
        }
    }

    Err(anyhow!(
        "Unable to locate a Starship config file for tmuxship (side={:?})",
        side
    ))
}