onpath 0.2.0

Get your tools on the PATH — cross-shell, cross-platform, zero fuss
Documentation
use std::path::{Path, PathBuf};

use crate::config::Position;
use crate::context::SystemContext;
use crate::shell::{Shell, ShellKind};

pub struct Zsh;

impl Shell for Zsh {
    fn kind(&self) -> ShellKind {
        ShellKind::Zsh
    }

    fn env_extension(&self) -> &'static str {
        ""
    }

    fn env_script(&self, dir: &Path, position: Position) -> String {
        super::posix_env_script(dir, position)
    }

    fn source_line(&self, env_script_path: &Path) -> String {
        super::posix_source_line(env_script_path)
    }

    fn rc_candidates(&self, ctx: &SystemContext) -> Vec<PathBuf> {
        // Zsh respects ZDOTDIR for config file location
        let zdotdir = ctx
            .env_var("ZDOTDIR")
            .map_or_else(|| ctx.home_dir().to_owned(), PathBuf::from);

        vec![zdotdir.join(".zshenv"), zdotdir.join(".zshrc")]
    }

    fn primary_rc(&self, ctx: &SystemContext) -> PathBuf {
        let zdotdir = ctx
            .env_var("ZDOTDIR")
            .map_or_else(|| ctx.home_dir().to_owned(), PathBuf::from);
        zdotdir.join(".zshenv")
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use super::*;

    #[test]
    fn env_script_prepend() {
        let script = Zsh.env_script(Path::new("/app/bin"), Position::Prepend);
        assert!(script.contains(r#"case ":${PATH}:""#));
        assert!(script.contains(r#"export PATH="/app/bin:$PATH""#));
    }

    #[test]
    fn env_script_append() {
        let script = Zsh.env_script(Path::new("/app/bin"), Position::Append);
        assert!(script.contains(r#"export PATH="$PATH:/app/bin""#));
    }

    #[test]
    fn rc_candidates_uses_zdotdir() {
        let mut env = HashMap::new();
        env.insert("ZDOTDIR".to_owned(), "/custom/zsh".to_owned());
        let ctx = SystemContext::with_home_and_env(PathBuf::from("/home/user"), env);
        let candidates = Zsh.rc_candidates(&ctx);
        assert!(candidates.contains(&PathBuf::from("/custom/zsh/.zshenv")));
    }

    #[test]
    fn rc_candidates_defaults_to_home() {
        let ctx = SystemContext::with_home(PathBuf::from("/home/user"));
        let candidates = Zsh.rc_candidates(&ctx);
        assert!(candidates.contains(&PathBuf::from("/home/user/.zshenv")));
        assert!(candidates.contains(&PathBuf::from("/home/user/.zshrc")));
    }

    #[test]
    fn primary_rc_is_zshenv() {
        let ctx = SystemContext::with_home(PathBuf::from("/home/user"));
        assert_eq!(Zsh.primary_rc(&ctx), PathBuf::from("/home/user/.zshenv"));
    }
}