gosuto 0.11.1

Gōsuto (ゴースト) — a cyberpunk terminal Matrix client with vim motions
use std::process;

pub struct CliArgs {
    pub profile: Option<String>,
}

pub fn parse_args() -> CliArgs {
    let mut args = std::env::args().skip(1);
    let mut profile = None;

    while let Some(arg) = args.next() {
        match arg.as_str() {
            "--profile" => {
                let name = args.next().unwrap_or_else(|| {
                    eprintln!("Error: --profile requires a value");
                    eprintln!("Usage: gosuto [--profile <name>]");
                    process::exit(1);
                });
                if !is_valid_profile_name(&name) {
                    eprintln!(
                        "Error: invalid profile name '{name}'. \
                         Must match [a-zA-Z0-9_-]+, max 64 characters."
                    );
                    process::exit(1);
                }
                profile = Some(name);
            }
            _ => {
                eprintln!("Error: unknown argument '{arg}'");
                eprintln!("Usage: gosuto [--profile <name>]");
                process::exit(1);
            }
        }
    }

    CliArgs { profile }
}

fn is_valid_profile_name(name: &str) -> bool {
    !name.is_empty()
        && name.len() <= 64
        && name
            .bytes()
            .all(|b| b.is_ascii_alphanumeric() || b == b'_' || b == b'-')
}

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

    #[test]
    fn valid_profile_names() {
        assert!(is_valid_profile_name("work"));
        assert!(is_valid_profile_name("user-1"));
        assert!(is_valid_profile_name("test_profile"));
        assert!(is_valid_profile_name("A"));
        assert!(is_valid_profile_name(&"a".repeat(64)));
    }

    #[test]
    fn invalid_profile_names() {
        assert!(!is_valid_profile_name(""));
        assert!(!is_valid_profile_name(&"a".repeat(65)));
        assert!(!is_valid_profile_name("foo/bar"));
        assert!(!is_valid_profile_name("foo\\bar"));
        assert!(!is_valid_profile_name("foo bar"));
        assert!(!is_valid_profile_name("foo.bar"));
    }
}