Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# vscode
.vscode

.config.bp
scripts/
26 changes: 13 additions & 13 deletions crates/commander-core/src/fmt.rs
Original file line number Diff line number Diff line change
@@ -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),
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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())?;
Expand All @@ -60,13 +60,13 @@ impl Debug for Command {
}


impl Debug for Application {
impl <Out> Display for Application<Out> {
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 {
Expand All @@ -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())?;
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
150 changes: 136 additions & 14 deletions crates/commander-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand All @@ -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<Out> {
name: &'static str,
version: &'static str,
description: &'static str,
pub cmds: Vec<Command>,
pub opts: Vec<Options>,
pub direct_args: Vec<Argument>,
pub out: Option<Out>
}

/// Represents a instance defined by `#[command]`.
Expand Down Expand Up @@ -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<Argument>,
Expand Down Expand Up @@ -237,10 +242,30 @@ pub struct Cmd {
pub struct Cli {
pub cmd: Option<Cmd>,
pub global_raws: HashMap<String, Raw>,
pub direct_args: Vec<Raw>,
pub direct_args: Option<Vec<Raw>>,
}

impl Application {
impl<Out> Application<Out> {
fn new(
name: &'static str,
version: &'static str,
description: &'static str,
cmds: Vec<Command>,
opts: Vec<Options>,
direct_args: Vec<Argument>,
) -> 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!
Expand Down Expand Up @@ -312,7 +337,7 @@ impl Cli {
Cli {
cmd: None,
global_raws: HashMap::new(),
direct_args: vec![],
direct_args: None,
}
}

Expand Down Expand Up @@ -360,7 +385,7 @@ impl Cli {

/// Inner function, dont use it.
#[doc(hidden)]
pub fn from(instances: &Vec<Instance>, app: &Application) -> Option<Cli> {
pub fn from <Out>(instances: &Vec<Instance>, app: &Application<Out>) -> Option<Cli> {
if instances.is_empty() {
None
} else {
Expand Down Expand Up @@ -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
}
}
})
Expand Down Expand Up @@ -558,7 +583,104 @@ impl Instance {
}
}

pub fn normalize(args: Vec<String>, app: &Application) -> Vec<Instance> {
type Handler<Out> = fn(&Vec<Raw>, Cli) -> Out;


pub struct Commander<Out> {
call_fns: Mutex<HashMap<String, Handler<Out>>>,
direct_fn: Mutex<Option<Handler<Out>>>,
name: &'static str,
version: &'static str,
description: &'static str
}
impl<Out> Commander<Out> {
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<Out>) {
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<Out>) {
let mut direct_fn = *self.direct_fn.lock().unwrap();
*direct_fn.borrow_mut() = Some(handler);
}

pub fn run(
&self,
cmds: Vec<Command>,
opts: Vec<Options>,
args: Vec<Argument>,
) -> Application<Out> {
let mut application = Application::new(
self.name,
self.description,
self.version,
cmds,
opts,
args,
);


let args = std::env::args().into_iter().collect::<Vec<String>>();
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 <Out>(args: Vec<String>, app: &Application<Out>) -> Vec<Instance> {
let mut instances = vec![];
let mut head = Instance::empty();
let mut args = args.into_iter().skip(1);
Expand Down Expand Up @@ -647,4 +769,4 @@ pub fn normalize(args: Vec<String>, app: &Application) -> Vec<Instance> {
}

instances
}
}
6 changes: 3 additions & 3 deletions crates/commander-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Loading