diff --git a/.gitignore b/.gitignore index f8f4c9d..48b0c22 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,8 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk - +# vscode +.vscode .config.bp scripts/ \ No newline at end of file diff --git a/crates/commander-core/src/fmt.rs b/crates/commander-core/src/fmt.rs index 1fef4a8..944c3ff 100644 --- a/crates/commander-core/src/fmt.rs +++ b/crates/commander-core/src/fmt.rs @@ -1,9 +1,9 @@ #![allow(unused_mut, dead_code)] -use std::fmt::{ Debug, Formatter, Result }; +use std::fmt::{ Formatter, Result, Display }; use crate::{ Command, Argument, ArgumentType, Application }; -impl Debug for Argument { +impl Display for Argument { fn fmt(&self, f: &mut Formatter) -> Result { match self.ty { ArgumentType::RequiredSingle => write!(f, "<{}>", self.name), @@ -14,14 +14,14 @@ impl Debug for Argument { } } -impl Debug for Command { +impl Display for Command { fn fmt(&self, f: &mut Formatter) -> Result { let mut max_len = 0; let mut arg_formats = String::new(); let mut lens = vec![]; for opt in &self.opts { - let arg_len = opt.arg.as_ref().map_or(0, |a| format!("{:?}", a).len()); + let arg_len = opt.arg.as_ref().map_or(0, |a| format!("{:}", a).len()); let used_space = opt.long.len() + opt.short.len() + arg_len; if used_space > max_len { @@ -32,7 +32,7 @@ impl Debug for Command { } for arg in &self.args { - arg_formats.push_str(&format!("{:?} ", arg)); + arg_formats.push_str(&format!("{:} ", arg)); } if self.opts.len() > 0 { @@ -48,7 +48,7 @@ impl Debug for Command { for opt in &self.opts { let used_space = lens.pop().unwrap_or_default(); - let arg_format = opt.arg.as_ref().map_or(String::new(), |a| format!("{:?}", a)); + let arg_format = opt.arg.as_ref().map_or(String::new(), |a| format!("{:}", a)); write!(f, " {}", format!("-{}, --{} {} {}", opt.short, opt.long, arg_format, " ".repeat(max_len - used_space)))?; write!(f, " {}\n", opt.desc.clone().unwrap_or_default())?; @@ -60,13 +60,13 @@ impl Debug for Command { } -impl Debug for Application { +impl Display for Application { fn fmt(&self, f: &mut Formatter) -> Result { let mut max_len = 0; let mut lens = vec![]; for opt in &self.opts { - let arg_len = opt.arg.as_ref().map_or(0, |a| format!("{:?}", a).len()); + let arg_len = opt.arg.as_ref().map_or(0, |a| format!("{:}", a).len()); let used_space = opt.long.len() + opt.short.len() + arg_len; if used_space > max_len { @@ -90,19 +90,19 @@ impl Debug for Application { write!(f, " OR {} ", self.name)?; for arg in self.direct_args.iter() { - write!(f, "{:?} ", arg)?; + write!(f, "{:} ", arg)?; } write!(f, "[options]")?; } - write!(f, "\n\n{}\n\n", self.desc)?; + write!(f, "\n\n{}\n\n", self.description)?; if !self.opts.is_empty() { write!(f, "Public options: \n")?; for opt in &self.opts { let used_space = lens.pop().unwrap_or_default(); - let arg_format = opt.arg.as_ref().map_or(String::new(), |a| format!("{:?}", a)); + let arg_format = opt.arg.as_ref().map_or(String::new(), |a| format!("{:}", a)); write!(f, " {}", format!("-{}, --{} {} {}", opt.short, opt.long, arg_format, " ".repeat(max_len - used_space)))?; write!(f, " {}\n", opt.desc.clone().unwrap_or_default())?; @@ -117,7 +117,7 @@ impl Debug for Application { let mut used_space = cmd.name.len() + 13; for arg in &cmd.args { - used_space += format!("{:?}", arg).len() + 1; + used_space += format!("{:}", arg).len() + 1; } if used_space > max_len { @@ -133,7 +133,7 @@ impl Debug for Application { write!(f, " {} ", cmd.name)?; for arg in &cmd.args { - write!(f, "{:?} ", arg)?; + write!(f, "{:} ", arg)?; } if cmd.opts.len() > 0 { diff --git a/crates/commander-core/src/lib.rs b/crates/commander-core/src/lib.rs index 26ce95a..d1cc87b 100644 --- a/crates/commander-core/src/lib.rs +++ b/crates/commander-core/src/lib.rs @@ -30,10 +30,11 @@ mod pattern; use std::ops::Index; use std::collections::HashMap; -use pattern::{ Pattern, PatternType }; +use pattern::{Pattern, PatternType}; pub use raw::Raw; +use std::borrow::BorrowMut; use std::process::exit; - +use std::sync::Mutex; /// The type of argument. /// /// they are: @@ -69,7 +70,7 @@ pub enum ArgumentType { /// For most of the time, you will not use it. #[doc(hidden)] #[derive(PartialEq, Eq)] -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Argument { pub name: String, pub ty: ArgumentType, @@ -91,12 +92,15 @@ pub struct Argument { /// # Note /// It's generated by `commander_rust`, and it should be readonly. /// -pub struct Application { - pub name: String, - pub desc: String, +#[derive(Debug)] +pub struct Application { + name: &'static str, + version: &'static str, + description: &'static str, pub cmds: Vec, pub opts: Vec, pub direct_args: Vec, + pub out: Option } /// Represents a instance defined by `#[command]`. @@ -141,6 +145,7 @@ pub struct Application { /// For most of the time, you will not use it. /// #[doc(hidden)] +#[derive(Debug)] pub struct Command { pub name: String, pub args: Vec, @@ -237,10 +242,30 @@ pub struct Cmd { pub struct Cli { pub cmd: Option, pub global_raws: HashMap, - pub direct_args: Vec, + pub direct_args: Option>, } -impl Application { +impl Application { + fn new( + name: &'static str, + version: &'static str, + description: &'static str, + cmds: Vec, + opts: Vec, + direct_args: Vec, + ) -> Self { + let mut application = Application { + name, + description, + version, + cmds, + opts, + direct_args, + out: None + }; + application.derive(); + application + } /// Deriving `#[option(-h, --help, "output usage information")]` /// and `#[option(-V, --version, "output the version number")]` for all `Command` and `Application`. /// Dont use it! @@ -312,7 +337,7 @@ impl Cli { Cli { cmd: None, global_raws: HashMap::new(), - direct_args: vec![], + direct_args: None, } } @@ -360,7 +385,7 @@ impl Cli { /// Inner function, dont use it. #[doc(hidden)] - pub fn from(instances: &Vec, app: &Application) -> Option { + pub fn from (instances: &Vec, app: &Application) -> Option { if instances.is_empty() { None } else { @@ -396,9 +421,9 @@ impl Cli { global_raws, direct_args: { if instances[0].is_empty() && !instances[0].args.is_empty() { - Raw::divide_cmd(&instances[0], &app.direct_args) + Some(Raw::divide_cmd(&instances[0], &app.direct_args)) } else { - vec![] + None } } }) @@ -558,7 +583,104 @@ impl Instance { } } -pub fn normalize(args: Vec, app: &Application) -> Vec { +type Handler = fn(&Vec, Cli) -> Out; + + +pub struct Commander { + call_fns: Mutex>>, + direct_fn: Mutex>>, + name: &'static str, + version: &'static str, + description: &'static str +} +impl Commander { + pub fn new(name: &'static str, version: &'static str, description: &'static str) -> Self { + Commander { + call_fns: Mutex::new(HashMap::new()), + direct_fn:Mutex::new(None), + name, + version, + description + } + } + + pub fn register_command_handler(&self, name: String, handler: Handler) { + let mut fns = self.call_fns.lock().unwrap(); + if !fns.contains_key(&name) { + fns.insert(name, handler); + } + } + pub fn register_direct_handler(&self, handler:Handler) { + let mut direct_fn = *self.direct_fn.lock().unwrap(); + *direct_fn.borrow_mut() = Some(handler); + } + + pub fn run( + &self, + cmds: Vec, + opts: Vec, + args: Vec, + ) -> Application { + let mut application = Application::new( + self.name, + self.description, + self.version, + cmds, + opts, + args, + ); + + + let args = std::env::args().into_iter().collect::>(); + let instances = normalize(args, &application); + let cli = Cli::from(&instances, &application); + + if let Some(cli) = cli { + if cli.has("help") || cli.has("h") { + // display sub-command usage + if cli.cmd.is_some() { + for cmd in &application.cmds { + if cmd.name == cli.get_name() { + println!("{:#}", cmd); + break; + } + } + } else { + // display cli usage + println!("{:#}", application); + } + } else if cli.has("version") || cli.has("V") { + println!("version: {}", self.version); + } else { + let fns = self.call_fns.lock().unwrap(); + if let Some(callback) = fns.get(&cli.get_name()) { + application.out = Some(callback(&cli.get_raws(), cli)); + } else { + if let Some(direct_args) = cli.direct_args.clone() { + let df = *self.direct_fn.lock().unwrap(); + + if let Some(f) = &df { + application.out = Some(f(&direct_args, cli)); + } else { + println!("ERRRRR"); + } + } else { + eprintln!( + "Unknown usage. Using `{} --help` for more help information.\n", + self.name + ); + } + } + } + } else { + println!("Using `{} --help` for more help information.", self.name); + } + + application + } +} + +pub fn normalize (args: Vec, app: &Application) -> Vec { let mut instances = vec![]; let mut head = Instance::empty(); let mut args = args.into_iter().skip(1); @@ -647,4 +769,4 @@ pub fn normalize(args: Vec, app: &Application) -> Vec { } instances -} \ No newline at end of file +} diff --git a/crates/commander-macros/Cargo.toml b/crates/commander-macros/Cargo.toml index f9e8549..808253b 100644 --- a/crates/commander-macros/Cargo.toml +++ b/crates/commander-macros/Cargo.toml @@ -10,10 +10,10 @@ license = "MIT" proc-macro = true [dependencies] -proc-macro2 = "0.4.24" -quote = "0.6.11" +proc-macro2 = "1.0" +quote = "1.0" lazy_static = "1.2.0" [dependencies.syn] -version = "0.15.26" +version = "1" features = ["full", "extra-traits", "parsing"] diff --git a/crates/commander-macros/src/lib.rs b/crates/commander-macros/src/lib.rs index 965589e..e415b99 100644 --- a/crates/commander-macros/src/lib.rs +++ b/crates/commander-macros/src/lib.rs @@ -12,14 +12,18 @@ use std::collections::HashMap; use lazy_static::lazy_static; use quote::quote; -use syn::{ Ident, ItemFn, parse_macro_input }; +use syn::{ Ident, ItemFn, parse_macro_input, ReturnType }; use tokens::{ CommandToken, OptionsToken}; +use std::sync::{Mutex}; use crate::errors::{DON_NOT_MATCH, ENTRY_ONLY_MAIN, NO_SUB_CMD_NAMES_MAIN, OPT_DUPLICATE_DEFINITION, compile_error_info, DIRECT_ONLY_ONCE}; use crate::tools::generate_call_fn; use crate::tokens::{PureArguments, check_arguments}; use syn::spanned::Spanned; +/// adds _commander_rust prefix to the name e.g. +/// prefix!("main") -> _commander_rs_main +/// prefix!("main", "silent") -> _commander_rs_main_silent macro_rules! prefix { ($($i: tt),*) => { { @@ -40,24 +44,14 @@ macro_rules! prefix { } } -macro_rules! import { - ($o: ident as $r: ident) => { - quote! { - use commander_rust::{ $o as $r }; - } - }; - ($o: ident as $r: ident from $f: path) => { - quote! { - use $f::{ $o as $r }; - } - } -} lazy_static! { - static ref COMMAND_OPTIONS: std::sync::Mutex>> = std::sync::Mutex::new(HashMap::new()); - static ref OPTIONS: std::sync::Mutex> = std::sync::Mutex::new(vec![]); - static ref GET_FN_NAMES: std::sync::Mutex> = std::sync::Mutex::new(vec![]); - static ref DIRECT_NAME: std::sync::Mutex> = std::sync::Mutex::new(None); + static ref COMMAND_OPTIONS: Mutex>> = Mutex::new(HashMap::new()); + static ref OPTIONS: Mutex> = Mutex::new(vec![]); + + // Ever declared command name will is pushed into here (compile time). + static ref GET_FN_NAMES: Mutex> = Mutex::new(vec![]); + static ref DIRECT_NAME: Mutex> = Mutex::new(None); } @@ -76,14 +70,11 @@ lazy_static! { #[proc_macro_attribute] pub fn command(cmd: TokenStream, method: TokenStream) -> TokenStream { let method: ItemFn = parse_macro_input!(method as ItemFn); - let ItemFn { - ident, - decl, - .. - } = &method; + let args = &method.sig.inputs; + let ret = &method.sig.output; + let ident = &method.sig.ident; let name = format!("{}", ident); let get_fn = Ident::new(&prefix!(name), ident.span()); - let cmd_token = Ident::new(&prefix!("Command"), ident.span()); let opts = COMMAND_OPTIONS.lock().unwrap(); let mut get_fn_names = GET_FN_NAMES.lock().unwrap(); let mut get_fns = vec![]; @@ -104,7 +95,7 @@ pub fn command(cmd: TokenStream, method: TokenStream) -> TokenStream { let command: CommandToken = parse_macro_input!(cmd as CommandToken); // generating call function, because we can't call unstable (uncertain quantity parameters) function let call_fn_name = Ident::new(&prefix!(name, "call"), ident.span()); - let call_fn = generate_call_fn(&decl.inputs, &call_fn_name, &ident); + let call_fn = generate_call_fn(args, &call_fn_name, ident, ret); let mut error_info = check_arguments(&command.args); if format!("{}", command.name) != "main" && format!("{}", command.name) != name { @@ -118,21 +109,12 @@ pub fn command(cmd: TokenStream, method: TokenStream) -> TokenStream { TokenStream::from(quote! { #error_info - fn #get_fn() -> #cmd_token { - let mut command = #command; - let mut fns = CALL_FNS.lock().unwrap(); + fn #get_fn() -> ::commander_rust::Command { + COMMANDER.register_command_handler(String::from(#name), #call_fn_name); - if !fns.contains_key(#name) { - fns.insert(String::from(#name), #call_fn_name); - } + let mut command = #command; + command.opts = vec![#(#get_fns(),)*]; - command.opts = { - let mut v = vec![]; - #( - v.push(#get_fns()); - )* - v - }; command } @@ -162,15 +144,11 @@ pub fn command(cmd: TokenStream, method: TokenStream) -> TokenStream { pub fn option(opt: TokenStream, method: TokenStream) -> TokenStream { let option: OptionsToken = parse_macro_input!(opt as OptionsToken); let method: ItemFn = parse_macro_input!(method as ItemFn); - let ItemFn { - ident, - .. - } = &method; + let ident = &method.sig.ident; let name = format!("{}", ident); let opt_name = format!("{}", option.long); let fn_name = prefix!(name, opt_name); let get_fn = Ident::new(&fn_name, option.long.span()); - let opt_token = Ident::new(&prefix!("Options"), ident.span()); let mut opts = COMMAND_OPTIONS.lock().unwrap(); let mut error_info = TokenStream2::new(); let mut all_opts = OPTIONS.lock().unwrap(); @@ -198,7 +176,7 @@ pub fn option(opt: TokenStream, method: TokenStream) -> TokenStream { TokenStream::from(quote! { #error_info - fn #get_fn() -> #opt_token { + fn #get_fn() -> ::commander_rust::Options { #option } @@ -236,18 +214,15 @@ pub fn option(opt: TokenStream, method: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn direct(pure_args: TokenStream, func: TokenStream) -> TokenStream { let func: ItemFn = parse_macro_input!(func as ItemFn); - let ItemFn { - ident, - decl, - .. - } = &func; + let ident = &func.sig.ident; + let ret = &func.sig.output; + let args = &func.sig.inputs; let name = format!("{}", ident); let pure_args: PureArguments = parse_macro_input!(pure_args as PureArguments); let direct_fn: &mut Option = &mut (*DIRECT_NAME.lock().unwrap()); let direct_get_fn = Ident::new(&prefix!(name), ident.span()); - let argument_ident = Ident::new(&prefix!("Argument"), ident.span()); let call_fn_name = Ident::new(&prefix!(name, "call"), ident.span()); - let call_fn = generate_call_fn(&decl.inputs, &call_fn_name, &ident); + let call_fn = generate_call_fn(args, &call_fn_name, ident, ret); let mut error_info: TokenStream2 = check_arguments(&pure_args.0); @@ -262,10 +237,8 @@ pub fn direct(pure_args: TokenStream, func: TokenStream) -> TokenStream { #func - fn #direct_get_fn() -> Vec<#argument_ident> { - let direct_fn: &mut Option, app: _commander_rust_Cli)> = &mut (*DIRECT_FN.lock().unwrap()); - - *direct_fn.borrow_mut() = Some(#call_fn_name); + fn #direct_get_fn() -> Vec<::commander_rust::Argument> { + COMMANDER.register_direct_handler(#call_fn_name); #pure_args } @@ -286,142 +259,36 @@ pub fn direct(pure_args: TokenStream, func: TokenStream) -> TokenStream { pub fn entry(pure_arguments: TokenStream, main: TokenStream) -> TokenStream { let pure_args: PureArguments = parse_macro_input!(pure_arguments as PureArguments); let main: ItemFn = parse_macro_input!(main as ItemFn); - let ItemFn { - ident, - .. - } = &main; + let ident = &main.sig.ident; + let ret = &main.sig.output; + let out = match ret { + ReturnType::Default => quote! { () }, + ReturnType::Type(_, t) => quote! { #t }, + }; let target = format!("{}", ident); - let opts = COMMAND_OPTIONS.lock().unwrap(); - let imports = vec![ - import!(Argument as _commander_rust_Argument), - import!(ArgumentType as _commander_rust_ArgumentType), - import!(Command as _commander_rust_Command), - import!(Options as _commander_rust_Options), - import!(Raw as _commander_rust_Raw), - import!(normalize as _commander_rust_normalize), - import!(Instance as _commander_rust_Instance), - import!(ls as _commander_rust_ls), - import!(Application as _commander_rust_Application), - import!(Cli as _commander_rust_Cli), - ]; - let get_fn = Ident::new(&prefix!("main"), ident.span()); - let app_token = Ident::new(&prefix!("Application"), ident.span()); - let get_fn_names = GET_FN_NAMES.lock().unwrap(); - let direct_fn = &(*DIRECT_NAME.lock().unwrap()); - let mut get_cmds_fns = vec![]; - let mut get_opts_fns = vec![]; let mut error_info = check_arguments(&pure_args.0); - // init can be used with fn main only + // entry can only be used with fn main. if target != String::from("main") { error_info = compile_error_info(ident.span(), ENTRY_ONLY_MAIN); } - if let Some(v) = opts.get("main") { - for i in v { - get_opts_fns.push(Ident::new(&prefix!("main", i), ident.span())); - } - } - for i in get_fn_names.iter() { - get_cmds_fns.push(Ident::new(&prefix!(i), ident.span())); - } - - let needed = quote! { + let entry = quote! { #error_info - mod _commander_rust_Inner { - use crate::_commander_rust_ls; - use crate::_commander_rust_Raw; - use crate::_commander_rust_Cli; - - type Raw = _commander_rust_Raw; - type Map = std::collections::HashMap, app: _commander_rust_Cli)>; - type Mutex = std::sync::Mutex; - - _commander_rust_ls! { - pub static ref CALL_FNS: Mutex = Mutex::new(Map::new()); - pub static ref DIRECT_FN: std::sync::Mutex, app: _commander_rust_Cli)>> = std::sync::Mutex::new(None); - } - pub const APP_NAME: &'static str = env!("CARGO_PKG_NAME"); - pub const VERSION: &'static str = env!("CARGO_PKG_VERSION"); - pub const DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION"); + commander_rust::ls! { + pub static ref COMMANDER: ::commander_rust::Commander<#out> = + ::commander_rust::Commander::new( + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION"), + env!("CARGO_PKG_DESCRIPTION") + ); } - use _commander_rust_Inner::{ CALL_FNS, DIRECT_FN, VERSION, DESCRIPTION, APP_NAME }; - #(#imports)* - #main }; - - // inject direct-functions' arguments or not - if let Some(df) = direct_fn { - let direct_get_fn = Ident::new(&prefix!(df), Span2::call_site()); - - TokenStream::from(quote! { - #needed - - fn #get_fn() -> #app_token { - let mut application = #app_token { - name: String::from(APP_NAME), - desc: String::from(DESCRIPTION), - opts: vec![], - cmds: vec![], - direct_args: vec![], - }; - - application.opts = { - let mut v = vec![]; - #( - v.push(#get_opts_fns()); - )* - v - }; - application.cmds = { - let mut v = vec![]; - #( - v.push(#get_cmds_fns()); - )* - v - }; - // inject direct-fns - application.direct_args = #direct_get_fn(); - - application - } - }) - } else { - TokenStream::from(quote!{ - #needed - - fn #get_fn() -> #app_token { - let mut application = #app_token { - name: String::from(APP_NAME), - desc: String::from(DESCRIPTION), - opts: vec![], - cmds: vec![], - direct_args: vec![], - }; - - application.opts = { - let mut v = vec![]; - #( - v.push(#get_opts_fns()); - )* - v - }; - - application.cmds = { - let mut v = vec![]; - #( - v.push(#get_cmds_fns()); - )* - v - }; - application - } - }) - } + entry.into() } /// Run cli now. @@ -430,56 +297,42 @@ pub fn entry(pure_arguments: TokenStream, main: TokenStream) -> TokenStream { /// See `Application` for more details. /// #[proc_macro] -pub fn run(_: TokenStream) -> TokenStream { - TokenStream::from(quote! { - { - // _commander_rust_main is generated by `entry` - // - let mut app = _commander_rust_main(); - let ins; - - app.derive(); - ins = _commander_rust_normalize(std::env::args().into_iter().collect::>(), &app); - - let cli = _commander_rust_Cli::from(&ins, &app); - let fns = CALL_FNS.lock().unwrap(); - - if let Some(cli) = cli { - if cli.has("help") || cli.has("h") { - // display sub-command usage - if cli.cmd.is_some() { - for cmd in &app.cmds { - if cmd.name == cli.get_name() { - println!("{:#?}", cmd); - break; - } - } - } else { - // display cli usage - println!("{:#?}", app); - } - } else if cli.has("version") || cli.has("V") { - println!("version: {}", VERSION); - } else { - if let Some(callback) = fns.get(&cli.get_name()) { - callback(&cli.get_raws(), cli); - } else if !cli.direct_args.is_empty() { - let df = *DIRECT_FN.lock().unwrap(); - - if let Some(f) = &df { - f(&cli.direct_args.clone(), cli) - } else { - println!("ERRRRR"); - } - } else { - eprintln!("Unknown usage. Using `{} --help` for more help information.\n", APP_NAME); - } - } - } else { - println!("Using `{} --help` for more help information.", APP_NAME); - } +pub fn run(input: TokenStream) -> TokenStream { + println!("{:#?}", input); + let mut get_cmds_fns:Vec = vec![]; + let mut get_opts_fns:Vec = vec![]; + let direct_fn = &(*DIRECT_NAME.lock().unwrap()); - app + // Options for main are global. For each option e.g. `--foo` we will collect + // identifier (in this example `_commander_rs_main_foo`) into + // `get_opts_fns`. + let opts = COMMAND_OPTIONS.lock().unwrap(); + if let Some(v) = opts.get("main") { + for i in v { + get_opts_fns.push(Ident::new(&prefix!("main", i), Span2::call_site())); } - }) -} \ No newline at end of file + } + + // For each registered command e.g. `find` we collect identifier + // (in this example `_commander_rs_find`) into `get_cmds_fns`. + let get_fn_names = GET_FN_NAMES.lock().unwrap(); + for i in get_fn_names.iter() { + get_cmds_fns.push(Ident::new(&prefix!(i), Span2::call_site())); + } + + let direct_get_fn = if let Some(df) = direct_fn { + let direct_get = Ident::new(&prefix!(df), Span2::call_site()); + quote! { #direct_get() } + } else { + quote! { vec![] } + }; + + let run = quote! { + COMMANDER.run( + vec![#(#get_cmds_fns(),)*], + vec![#(#get_opts_fns(),)*], + #direct_get_fn + ) + }; + run.into() +} diff --git a/crates/commander-macros/src/tokens.rs b/crates/commander-macros/src/tokens.rs index dac18ed..44bb086 100644 --- a/crates/commander-macros/src/tokens.rs +++ b/crates/commander-macros/src/tokens.rs @@ -23,22 +23,22 @@ impl ToTokens for ArgumentType { match self { &ArgumentType::RequiredSingle => { (quote! { - _commander_rust_ArgumentType::RequiredSingle + ::commander_rust::ArgumentType::RequiredSingle }).to_tokens(tokens); }, &ArgumentType::RequiredMultiple => { (quote! { - _commander_rust_ArgumentType::RequiredMultiple + ::commander_rust::ArgumentType::RequiredMultiple }).to_tokens(tokens); }, &ArgumentType::OptionalSingle => { (quote! { - _commander_rust_ArgumentType::OptionalSingle + ::commander_rust::ArgumentType::OptionalSingle }).to_tokens(tokens); }, &ArgumentType::OptionalMultiple => { (quote! { - _commander_rust_ArgumentType::OptionalMultiple + ::commander_rust::ArgumentType::OptionalMultiple }).to_tokens(tokens); } } @@ -60,7 +60,7 @@ impl ToTokens for Argument { } = self; let name = format!("{}", name); let expand = quote! { - _commander_rust_Argument { + ::commander_rust::Argument { name: String::from(#name), ty: #ty, } @@ -154,7 +154,7 @@ impl ToTokens for CommandToken { quote!(None) }; let expand = quote! { - _commander_rust_Command { + ::commander_rust::Command { name: String::from(#name), args: vec![#( #args ),*], desc: #desc, @@ -279,7 +279,7 @@ impl ToTokens for OptionsToken { }; let expand = quote! { - _commander_rust_Options { + ::commander_rust::Options { short: String::from(#short), long: String::from(#long), arg: #arg, diff --git a/crates/commander-macros/src/tools.rs b/crates/commander-macros/src/tools.rs index e529e37..43df924 100644 --- a/crates/commander-macros/src/tools.rs +++ b/crates/commander-macros/src/tools.rs @@ -1,8 +1,8 @@ +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; use syn::punctuated::Punctuated; -use syn::{ FnArg, Ident }; use syn::token; -use quote::quote; -use proc_macro2::{ TokenStream as TokenStream2 }; +use syn::{ReturnType, FnArg, Ident}; /// Generate inputs of command processing function. /// @@ -10,11 +10,16 @@ use proc_macro2::{ TokenStream as TokenStream2 }; /// But we need a common way to call it, so we need to generate inputs tokens needed. #[doc(hidden)] -pub fn generate_call_fn(inputs: &Punctuated, call_fn_name: &Ident, fn_name: &Ident) -> TokenStream2 { +pub fn generate_call_fn( + inputs: &Punctuated, + call_fn_name: &Ident, + fn_name: &Ident, + ret: &ReturnType, +) -> TokenStream2 { let mut tokens: Vec = vec![]; for (idx, arg) in inputs.iter().enumerate() { - if let FnArg::Captured(cap) = arg { + if let FnArg::Typed( cap) = arg { let ty = &cap.ty; if idx < inputs.len() - 1 { @@ -49,7 +54,7 @@ pub fn generate_call_fn(inputs: &Punctuated, call_fn_name: } (quote! { - fn #call_fn_name(raws: &Vec<_commander_rust_Raw>, cli: _commander_rust_Cli) { + fn #call_fn_name(raws: &Vec<::commander_rust::Raw>, cli: ::commander_rust::Cli) #ret { #fn_name(#(#tokens,)*) } }).into() diff --git a/docs/README_CN.md b/docs/README_CN.md index ab77441..d26c809 100644 --- a/docs/README_CN.md +++ b/docs/README_CN.md @@ -45,8 +45,8 @@ ##### 从`Github`下载 ```toml -[dependencies.commander_rust] -git = "https://github.com/MSDimos/commander_rust" +[dependencies.commander-rust] +git = "https://github.com/MSDimos/commander-rust" branch = "master" ``` @@ -54,7 +54,7 @@ branch = "master" ```toml [dependencies] -commander_rust = "1.1.3" # 指定其他任意你需要的版本 +commander-rust = "1.1.3" # 指定其他任意你需要的版本 ``` #### 使用它 diff --git a/homepage/dist b/homepage/dist deleted file mode 160000 index 9a8c9b8..0000000 --- a/homepage/dist +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9a8c9b82f90d74d97b41fd855a6fc615786d7107 diff --git a/homepage/public/readme.html b/homepage/public/readme.html index f2fd190..f1bc553 100644 --- a/homepage/public/readme.html +++ b/homepage/public/readme.html @@ -303,7 +303,7 @@

other languages

中文文档

why this ?

For a long time, developing cli in Rust is difficult. The community offers a wide range of solutions. Yes, they're excellent, but they're not very simple.

Inspired by commander.js & rocket.rs, the crate was born.

features

  • API friendly
  • easy to use
  • support for approximate dynamic language
  • low performance loss
  • automatically support for --version & --help
  • automatically run corresponding commands

limit

If you want to use this crate, please guarantee that you have follow rules below:

  • using Rust 2018 (full proc macro support is required, including [proc_macro] & [proc_macro_attribute])
  • using cargo (cargo will produce some environment variable according to Cargo.toml, we need that)
  • be familiar with Rust (because it's developed for Rust )

As a reference, my versions are:

  • cargo: cargo 1.35.0-nightly (95b45eca1 2019-03-06)
  • rustc: rustc 1.35.0-nightly (e68bf8ae1 2019-03-11)
  • Linux kernal: 4.15.0-47-generic
  • Ubuntu: 16.04

usage

install commander-rust

Two ways supported: from Github or crates.io. -The difference between them is that Github is latest but unstable and crates.io is stable but might not be latest.

install from Github

install from crates.io

using it

We offer a simple but complete example, you can learn all through it. +The difference between them is that Github is latest but unstable and crates.io is stable but might not be latest.

install from Github

install from crates.io

using it

We offer a simple but complete example, you can learn all through it. Yes, That's all. Very easy!

try it

try to input [pkg-name] --help.

version & description & cli-name?

version, description, cli-name of application are from Cargo.toml.

For instance:

direct

If you don't want to define a sub-command, you can use #[direct]. What's direct? In some situations, for instance, if you want to develop a CLI which could be called like rm ./* -rf. diff --git a/homepage/public/readme.md b/homepage/public/readme.md index 7a8432c..e1d2c36 100644 --- a/homepage/public/readme.md +++ b/homepage/public/readme.md @@ -41,8 +41,8 @@ The difference between them is that `Github` is latest but unstable and `crates. ##### install from `Github` ```toml -[dependencies.commander_rust] -git = "https://github.com/MSDimos/commander_rust" +[dependencies.commander-rust] +git = "https://github.com/MSDimos/commander-rust" branch = "master" ``` @@ -50,7 +50,7 @@ branch = "master" ```toml [dependencies] -commander_rust = "1.1.3" # or other version you want to install +commander-rust = "1.1.3" # or other version you want to install ``` #### using it diff --git a/src/lib.rs b/src/lib.rs index 67c07dc..51d0100 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -pub use commander_core::{ Argument, ArgumentType, Command, Options, normalize, Raw, Application, Cli, Cmd, Instance }; +pub use commander_core::{ Argument, ArgumentType, Command, Options, normalize, Raw, Application, Cli, Cmd, Instance, Commander }; pub use commander_macros::{ command, option, run, entry, direct }; pub use lazy_static::{ lazy_static as ls }; \ No newline at end of file