use lexopt::ValueExt; use crate::is_valid_name; use std::collections::HashMap; pub struct Subcommands { subcommands: HashMap, pub script: String, pub inner_parser: lexopt::Parser, } impl Subcommands { pub fn parse(mut parser: lexopt::Parser) -> Result { use lexopt::prelude::*; use std::fs::File; use std::io::{BufReader, prelude::*}; let script = parser.value()?.string()?; let mut subcommands: HashMap = HashMap::new(); let file = File::open(&script).map_err(|err| err.to_string())?; let reader = BufReader::new(file); for line in reader.lines() { let line = line.map_err(|err| err.to_string())?; //skip shebang if line.starts_with("#!") { continue; } if let Some(line) = line.strip_prefix("#=") { let (name, args) = line .split_once(' ') .ok_or("Invalid subcommand declaration")?; if !is_valid_name(name) { return Err("Invalid subcommand name: {name}".into()); } subcommands.insert(name.to_string(), args.to_string()); } else { break; } } Ok(Self { subcommands, script, inner_parser: parser, }) } pub fn get_current_subcommand_args(&mut self) -> Result<(String, String), lexopt::Error> { let subcommand = self.inner_parser.value()?.string()?; self.subcommands .get(&subcommand) .map(|args| (subcommand, args.to_owned())) .ok_or("Unknown subcommand".into()) } }