1 个不稳定版本
0.1.0 | 2022年11月28日 |
---|
#62 in #quick
34KB
636 代码行数(不含注释)
macro_clap
一种快速便捷的方式来实现命令行参数解析,具有自动生成的彩色使用说明,以及支持选项和参数分支的功能
示例
use macro_clap::*;
const INTRODUCTION: &'static str = "Whatever you want your intro to be";
cli!(
const ARG_PARSER: ArgParser<INTRODUCTION> = [
branch!(action as ActionEnum {
"copy" |> Copy => {
arg!(source as String),
arg!(dest as String)
},
"delete" |> Delete => {
arg!(source as String)
},
"modify" |> Modify => {
branch!(modif_type as ModifType {
"replace" |> Replace => {},
"append" |> Append => {}
}),
arg!(source as String),
arg!(text as String),
maybe!(encoding as (Option<String>)),
opt!(options as ModifyOptions {
interleave: ["--interleave"] -> (GrabLast<char>)
})
}
}),
opt!(options as OptionStruct {
verbose: ["-v", "--verbose"] -> (Counter<u8>),
explain: ["-x", "--explain"] -> Flag
}),
collect!(rest as (Vec<String>))
]
);
fn main() {
match ARG_PARSER.parse_args() {
Ok(args) => {
println!("{:?}", args);
},
Err(e) => {
println!("{e}");
return;
}
};
}
使用说明
如果 Err(String)
的情况在控制台中打印,你的代码将具有以下行为
- 在命令行中调用
your_crate
将在控制台中打印出介绍信息以及使用说明 - 调用
your_crate --help
将只打印出使用说明 - 调用
your_crate (一些错误的参数配置)
将打印出错误信息和使用说明 - 如果提供了过多的参数,并且没有设置任何
collect!
宏,它将打印出错误信息和使用说明
限制
在 macro_clap 中,所有以 '-' 开头的参数都被视为选项,其余的被视为普通参数。你对于错误信息的控制非常有限,它们可能有时对经验不足的用户不太有用。这是因为 macro_clap 优先考虑代码的简洁性而不是可用性,适合那些想快速编写功能 CLI 而不需要过多考虑实现细节的人,例如制作原型版本。
语法
// cli! is the root of your command line interface
// SomeUniqueType is just a type that the macro needs to make the cli
// You CAN make multiple cli! in the same file or same crate, as long as their types are not shared
// YOUR_INTRODUCTION must be either a &'static str or a const &'static str
// Once your cli! macro is constructed, use YOUR_CONST_NAME.parse_args() to parse the arguments
// The return value of YOUR_CONST_NAME.parse_args() is Result<(Arguments, String)>
// where Arguments is the tuple of the result of the parsing of all arguments
cli!(
const YOUR_CONST_NAME: SomeUniqueType<YOUR_INTRODUCTION> = [
/* list of all the arguments */
]
)
// This tells the macro to wait for an argument and to parse it as ArgType
// If no argument is passed, the macro will fail
// ArgType must be String, bool, or an integer
arg!(arg_name as ArgType)
// This tells the macro to wait for an argument and to parse it as Some(ArgType)
// However, unlike arg!, maybe! will not fail if no argument is given, but return None instead
// ArgType must be String, bool, or an integer
// Please do not forget to wrap ArgType in an Option and to surrond everything by parentheses
maybe!(maybe_arg_name as (Option<ArgType>))
// This tells the macro to wait for a keyword in the list
// If no keyword is passed, or if the keyword is not present in the list, the macro will fail
// BranchEnum is the type that will be returned by the branch! macro
// BranchEnum is automatically implemented by the macro, so make sure that it is unique
// Variants of BranchEnum are tuple variants, and contain the results of the arguments specific to their own path
branch!(branch_name as BranchEnum {
"keyword_1" |> Variant1 => {
/* list of args if keyword_1 */
},
"keyword_2" |> Variant2 => {
/* list of args if keyword_2 */
},
// You can make as many keywords as you want
}),
// This tells the macro to start parsing as many options as possible
// When the macro stops finding options, it just continues
// Lists of keywords related to options can be for example ["-v", "--verbose"]
// OptionTypes dictates how the options are handled
// OptionTypes are Counter, Flag, FlagCounter, GrabFirst, GrabLast and GrabAll
// Please see their documentation for more information about how they operate
// Please make sure that every OptionType is surrounded by parenthesis if it is a generic type
// i.e. (Counter<i8>) or (GrabFirst<String>)
opt!(option_group_name as OptionStruct {
option_1_name: [ /* list of all the keywords related to option 1 */ ] -> OptionType1,
option_2_name: [ /* list of all the keywords related to option 2 */ ] -> OptionType2,
// You can make as many options as you want
}),
// This will dump every argument left over by the previous parsing into a Vec<String>
// Please note that the return type of collect! MUST be (Vec<String>)
// Please make sure that nothing follows a collect!, as it will never recieve any arguments
collect!(rest as (Vec<String>))