use clap::{ArgMatches, Command}; use mize::item::ItemData; use std::{collections::HashMap, ffi::OsString}; use mize::prelude::*; #[unsafe(no_mangle)] pub extern "C" fn part_cli() -> MizeResult<()> { include_native!("Command", clap::Command, { associated: [new(name: String)], //methods: [arg(arg: clap::Arg), subcommand(cmd: clap::Command)] }); opt("state") .fun(Box::new(|| { let mize = get_global_mize().unwrap(); let state = CliPartState { cmds: HashMap::new(), current_cmd_name: "marts-cli".to_string(), actions: HashMap::new(), parsers: Some(Vec::new()), mize: mize.clone(), }; Ok(ItemData::from_native(state)?) })); method("set_command", |args| { let mut state = get_config("self.state")?.native_mut::()?; let cmd = args.get_path("0")?.native::()?; state.current_cmd_name = cmd.to_owned(); if !state.cmds.contains_key(&*cmd) { state.cmds .insert((*cmd).to_owned(), Command::new((*cmd).to_owned())); } Ok(ItemData::new()) }); method("subcommand", |args| { let mut state = get_config("self.state")?.native_mut::()?; let subcmd = args.get_path("0")?.native_take::()?; let action = args.get_path("1")?; let name = subcmd.get_name().to_string(); let cur_cmd_name = state.current_cmd_name.clone(); let cmd = state .cmds .remove(&cur_cmd_name) .unwrap() .subcommand(subcmd); state.cmds.insert(cur_cmd_name.clone(), cmd); state.actions.insert(name, action); Ok(ItemData::new()) }); method("run", |args| { let cmdline = args.get_path("0")?.native_take::>()?; let mut state = get_config("self.state")?.native_mut::()?; let cmd_name = cmdline.iter().nth(0).ok_or(mize_err!("empty cmdline"))?; let cmd = state.cmds.remove(cmd_name).ok_or(mize_err!("cmd {} not found in CliPart", cmd_name))?; let matches = cmd.get_matches_from(cmdline); let sub_name = matches.subcommand_name().ok_or(mize_err!("subcommand not found"))?; let sub_matches = matches.subcommand_matches(sub_name).ok_or(mize_err!("subcommand matches not found"))?; let action = state.actions.remove(sub_name).ok_or(mize_err!("action for subcommand not found"))?; let mut args = ItemData::new(); args.set_path("0", ItemData::from_native(sub_matches.clone())?); action.call(args)?; Ok(ItemData::new()) }); // TODO in future.... // Register methods from the impl block //CliPartState::methods_from_impl()?; Ok(()) } pub struct CliPartState { cmds: HashMap, current_cmd_name: String, actions: HashMap, parsers: Option) -> MizeResult<()> + Send + Sync + 'static>>>, mize: Mize, } /* #[part_impl] impl CliPartState { pub fn set_command(&mut self, cmd: &str) { self.current_cmd_name = cmd.to_owned(); if !self.cmds.contains_key(cmd) { self.cmds .insert(cmd.to_owned(), Command::new(cmd.to_owned())); } } pub fn subcommand( &mut self, subcmd: Command, action: Box MizeResult<()> + Send + Sync + 'static>, ) -> MizeResult<()> { let name = subcmd.get_name().to_string(); let cmd = self .cmds .remove(&self.current_cmd_name) .unwrap() .subcommand(subcmd); self.cmds.insert(self.current_cmd_name.clone(), cmd); self.actions.insert(name, action); Ok(()) } /* pub fn add_sub_parser) -> MizeResult<()> + Send + Sync + 'static>( &mut self, parser: T, ) -> MizeResult<()> { self.parsers.as_mut().unwrap().push(Box::new(parser)); Ok(()) } */ pub fn with_cmd( &mut self, func: fn(cmd: Command) -> MizeResult, ) -> MizeResult<()> { let cmd = self.cmds.remove(&self.current_cmd_name).ok_or(mize_err!( "current command {} not found", self.current_cmd_name ))?; let cmd = func(cmd)?; self.cmds.insert(self.current_cmd_name.clone(), cmd); Ok(()) } pub fn run(&mut self, cmdline: Vec) -> MizeResult<()> { let cmd_name = cmdline.iter().nth(0).ok_or(mize_err!("empty cmdline"))?; let cmd = self.cmds.remove(cmd_name).ok_or(mize_err!("cmd {} not found in CliPart", cmd_name))?; let matches = cmd.get_matches_from(cmdline); let sub_name = matches.subcommand_name().ok_or(mize_err!("subcommand not found"))?; let sub_matches = matches.subcommand_matches(sub_name).ok_or(mize_err!("subcommand matches not found"))?; let action = self.actions.remove(sub_name).ok_or(mize_err!("action for subcommand not found"))?; action(sub_matches, self.mize.clone())?; Ok(()) } } */