Command Line Argument Parser for Rust
Dual-licensed under Apache 2.0 or MIT.
Create your command-line parser, with all of the bells and whistles, declaratively or procedurally.
For more details, see:
⚡ Zero-boilerplate commandline argument parsing in Rust
Command Line Argument Parser for Rust
Dual-licensed under Apache 2.0 or MIT.
Create your command-line parser, with all of the bells and whistles, declaratively or procedurally.
For more details, see:
see thunder's CI-failures.
This example
#![feature(proc_macro)]
extern crate thunder;
extern crate clap;
use thunder::thunderclap;
struct Loki;
#[thunderclap(example: Option<String>: "Error here")]
impl Loki {
fn hello() {
println!("Hello, {:?}!", Self::example());
}
}
fn main() {
Loki::start();
}
This is because of over-simplistic string parsing in the custom attribute parameters 😅
This issue replaced #16
For example, it's not clear how to run app with more than one parameter:
/// App
#[thunderclap]
impl App {
/// run
fn run<'a, 'b>(token: &'a str, listening_address: &'b str) {
println!("Hello {}, my address is {}", token, listening_address);
}
}
error[E0599]: no function or associated item named `run` found for type `clap::App<'_, '_>` in the current scope
--> src\main.rs:28:1
|
28 | #[thunderclap]
| ^^^^^^^^^^^^^^ function or associated item not found in `clap::App<'_, '_>`
error: aborting due to previous error
This code
#![feature(proc_macro)]
extern crate thunder;
extern crate clap;
use thunder::thunderclap;
struct Loki;
#[thunderclap(example: String: "Error, here")]
impl Loki {
fn hello() {
println!("Hello, world!");
}
}
fn main() {
Loki::start();
}
will cause a program to panic when running the hello
hook without a name, which should be optional!
This issue replaces #16
The Loki example does not compile.
$ cargo run help
Compiling test-thunder v0.1.0 (/home/xxx/tmp/test-thunder)
error: custom attribute panicked
--> src/main.rs:9:1
|
9 | #[thunderclap(example: Option<String>: "Error, here", another_example: String: "No error, here")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: index out of bounds: the len is 1 but the index is 1
Running on edition = "2018"
:
$ rustc --version
rustc 1.33.0-nightly (adbfec229 2018-12-17)
#[thunderclap(drunk: bool: "Thor drinks a lot", hammers: Option<u8>: "This isn't a joke about being drunk")]
hmmmm
#[thunderclap(drunk: bool = "Thor drinks a lot", hammers: Option<u8> = "This isn't a joke about being drunk")]
[makes me more happy]
Given this code:
#[thunderclap]
impl Thor {
/// Print a test message
fn test(x: &str) {
println!("Hello {}", x);
}
/// Start the daemon
fn daemonize() {
println!("Trying to daemonize...");
}
}
the following --help
is generated:
Thor
USAGE:
wgd [SUBCOMMAND]
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
daemonize
help Prints this message or the help of the given subcommand(s)
test Print a test message
Note the lack of a description for the daemonize
subcommand. Notably, when a parameter is added, the description is picked up on
A minimal reproducible code can be found here, along with the compile erro, in comma_error.rs file: https://gist.github.com/gugahoa/25b79588ab566360ef586e57cbef993d
Hello!
After talking about thunder with @spacekookie, she told me about a effort to rewrite thunder to have a better usability and code.
Thinking about that, I thought about proposing a new way to write thunder apps.
So far my proposal would make a simple hello world look like this:
#![feature(use_extern_macros)]
extern crate thunder_derive;
extern crate thunder;
#[derive(ThunderApp)]
struct Thor {
/// Bla bla bl
#[thunder(take_value = false)] // Default is to take value
drunk: bool,
/// What will be Thor's age today
#[thunder(default_value = 1342)] // Can configure flag default value
age: i32
}
#[thunderclap]
impl Thor {
/// This is a subcommand, as before
fn hello(&self, name: Option<&str>) {
println!("Hello, {}! Nice to meet you, I'm Thor and I'm {} years old", name.unwrap_or("world"), self.age);
}
fn me(&self) {
let drunk = if self.drunk {
"drunk!"
} else {
"not drunk!"
};
println!("Huh, me? I'm Thor! And I'm {}");
}
}
fn main() {
Thor::start();
}
This is strongly inspired by structopt.
The main idea is to have global args parsing work like normal args do in structopt, and subcommands work as they work right now. Thus being more flexible, while still being fast to iterate.
I couldn't think about how to make subcommand arguments as flexible, but it's on my list of things to improve too
Hi, check this code out:
use thunder::thunderclap;
struct MyApp;
#[thunderclap]
impl MyApp {
fn hello(name: &str) -> Result<&str,()> {
println!("Hello {}", name);
}
}
fn main() {
MyApp::hello("kat");
}
Compilation errors:
$ cargo check
Checking test-thunder v0.1.0 (/home/xxx/tmp/test-thunder)
error[E0308]: mismatched types
--> src/main.rs:5:1
|
5 | #[thunderclap]
| ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found ()
|
= note: expected type `std::result::Result<&str, ()>`
found type `()`
error[E0308]: match arms have incompatible types
--> src/main.rs:5:1
|
5 | #[thunderclap]
| ^^^^^^^^^^^^^^
| |
| expected enum `std::result::Result`, found ()
| match arm with an incompatible type
|
= note: expected type `std::result::Result<&str, ()>`
found type `()`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
error: Could not compile `test-thunder`.
I see two issues here:
thunderclap
is "stealing" the error positioning, which is unfortunate because on large codebases it could make hard to understand where exactly is the errorCorrect error expected:
$ cargo_check
Checking test-thunder v0.1.0 (/home/xxx/tmp/test-thunder)
error[E0308]: mismatched types
--> src/main.rs:7:45
|
7 | fn hello(name: &str) -> Result<&str,()> {
| _____________________________________________^
8 | | println!("Hello {}", name);
9 | | }
| |_____^ expected enum `std::result::Result`, found ()
|
= note: expected type `std::result::Result<&str, ()>`
found type `()`
Running on edition = "2018"
:
$ rustc --version
rustc 1.33.0-nightly (adbfec229 2018-12-17)
Opinions?
This means arguments not bound to a subcommand. The usage string for such an option would look as follows
tool [global options] <command> [local options]
This is analogue to how docopt allows you to handle options
Trying to define subcommands such as the following fails:
#[thunderclap]
impl Thor {
/// Print a test message
fn test(x: &str) {
println!("Hello {}", x);
}
/// Start the daemon
fn daemonize(bar: u8) {
println!("Trying to daemonize... (bar={})", bar);
}
}
with this error:
error[E0308]: mismatched types
--> src/main.rs:35:1
|
35 | #[thunderclap]
| ^^^^^^^^^^^^^^ expected u8, found &str
|
= note: expected type `u8`
found type `&str`
It'd be nice if at least everything implementing From<&str>
was supported, failing the program if the conversion fails
I have following toml
[dependencies]
clap = "2"
thunder = "0.3"
Code is Thor example.
Output:
Compiling winapi v0.3.5
Compiling sample_app v0.1.0 (file:///C:/Users/Alex/Documents/Repo/sample_app)
Compiling atty v0.2.10
Compiling clap v2.31.2
Compiling thunder v0.3.1
error: custom attribute panicked
--> src\main.rs:10:1
|
10 | #[thunderclap(drunk: bool = "Bla bla bla")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: index out of bounds: the len is 2 but the index is 2
error: aborting due to previous error
error: Could not compile `sample_app`.
To learn more, run the command again with --verbose.
Process finished with exit code 101
Consider this simple snippet:
use thunder;
use clap;
use thunder::thunderclap;
struct MyApp;
#[thunderclap(param: String: "A global var")]
impl MyApp {
/// Scan a directory
fn scan(source_dir: String) {
println!("param={}", param);
}
}
fn main() {
MyApp::start();
}
returns an error when running compiling:
$ cargo run
Compiling test-thunder v0.1.0 (/home/xxx/tmp/test-thunder)
error[E0425]: cannot find value `param` in this scope
--> src/main.rs:8:1
|
8 | #[thunderclap(param: String: "A global var")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
or also
$ cargo run --param hey
error: Found argument '--param' which wasn't expected, or isn't valid in this context
USAGE:
cargo run [OPTIONS] [--] [args]...
For more information try --help
How are global variable supposed to be used? Can you help with some more detailed examples?
thanks
Currently, generated impl blocks are always for Thor
.
Minimal example can be found here, in panic.rs, along with output: https://gist.github.com/gugahoa/25b79588ab566360ef586e57cbef993d
😭
It could enable more features and make the code base easier to work with and contribute to
Actual functionality tbd
When i didn't provide a valid boolean, i got a not so nice error message:
thor bla aged
thread 'main' panicked at 'Failed to parse value. Double check!: ParseBoolError { _priv: () }', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
Would it be possible to instead print something like:
Error: <drunk> needs to be "true" or "false"
or something similar?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.