pulsedeck 0.1.8

A cyber-synthwave internet radio player and smart tape recorder for your terminal
use std::path::Path;
use std::process::Command;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Platform {
    Linux,
    Macos,
    Windows,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CommandSpec {
    pub program: String,
    pub args: Vec<String>,
}

pub fn open_containing_folder(path: &Path) -> Result<(), String> {
    let folder = path
        .parent()
        .ok_or_else(|| format!("{} has no containing folder", path.display()))?;
    let spec = open_folder_command_spec(folder, current_platform());

    let status = Command::new(&spec.program)
        .args(&spec.args)
        .status()
        .map_err(|err| format!("Could not launch {}: {err}", spec.program))?;

    if status.success() {
        Ok(())
    } else {
        Err(format!("{} exited with status {}", spec.program, status))
    }
}

pub fn open_folder_command_spec(folder: &Path, platform: Platform) -> CommandSpec {
    let folder = folder.to_string_lossy().to_string();

    match platform {
        Platform::Linux => CommandSpec {
            program: "xdg-open".to_string(),
            args: vec![folder],
        },
        Platform::Macos => CommandSpec {
            program: "open".to_string(),
            args: vec![folder],
        },
        Platform::Windows => CommandSpec {
            program: "explorer.exe".to_string(),
            args: vec![folder],
        },
    }
}

fn current_platform() -> Platform {
    if cfg!(target_os = "macos") {
        Platform::Macos
    } else if cfg!(target_os = "windows") {
        Platform::Windows
    } else {
        Platform::Linux
    }
}

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

    #[test]
    fn linux_opens_parent_with_xdg_open() {
        let spec =
            open_folder_command_spec(Path::new("/tmp/recordings/Synthwave"), Platform::Linux);
        assert_eq!(spec.program, "xdg-open");
        assert_eq!(spec.args, vec!["/tmp/recordings/Synthwave"]);
    }

    #[test]
    fn macos_opens_parent_with_open() {
        let spec =
            open_folder_command_spec(Path::new("/tmp/recordings/Synthwave"), Platform::Macos);
        assert_eq!(spec.program, "open");
        assert_eq!(spec.args, vec!["/tmp/recordings/Synthwave"]);
    }

    #[test]
    fn windows_opens_parent_with_explorer() {
        let spec = open_folder_command_spec(
            &PathBuf::from(r"C:\recordings\Synthwave"),
            Platform::Windows,
        );
        assert_eq!(spec.program, "explorer.exe");
        assert_eq!(spec.args, vec![r"C:\recordings\Synthwave"]);
    }
}