Giter Club home page Giter Club logo

gumdrop's People

Contributors

alexmaco avatar cole-miller avatar dansnow avatar eijebong avatar murarth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

gumdrop's Issues

define default from constant

I recently switched a project from Structopt to Gumdrop and am generally quite happy with the change. However, one thing I've not been able to figure out how to do is to use a const to define a default value.

Essentially, I define a default port and use this in several places in the code:

/// Constant defining Goose's default port when running a Gaggle.
const DEFAULT_PORT: &str = "5115";

One of the places I was able to use it with structopt was in defining the default value for a couple of run-time configuration options. Is there any way to do this with gumdrop?

For example, if I try this:

    /// Sets port Manager listens on
    #[options(no_short, default = DEFAULT_PORT, meta = "PORT")]
    pub manager_bind_port: u16,

I get the following error:

error: expected literal
    --> src/lib.rs:1945:35
     |
1945 |     #[options(no_short, default = DEFAULT_PORT, meta = "PORT")]
     |                                   ^^^^^^^^^^^^

Documentation should mention how to accept filenames as arguments.

A filename or path is not a String, but OsString. I don't see any mention of OS strings in crate-level documentation for gumdrop.

Also I see parse(try_from_str and parse(from_str, but I don't see the exhausive list of what I can put into parse(...). Is there from_os_str?

`help` magic option is undocumented?

As far as I can tell, if you put a help option in your options struct, gumdrop magically notices it and adds behavior to print out a help messages for you. Also as far as I can tell, nowhere in the docs or examples does it actually talk about this.

Multiple doc attributes are not supported, and multi-line doc comments retain their exact whitespace

#[derive(Debug, gumdrop::Options)]
struct Args {
    /// Which base58 alphabet to decode/encode with [possible values: bitcoin, monero,
    /// ripple, flickr or custom(abc...xyz)]
    alphabet: Alphabet,

    help: bool
}

This will only display the first line of doc comment in --help.


#[derive(Debug, gumdrop::Options)]
struct Args {
     /** Which base58 alphabet to decode/encode with [possible values: bitcoin, monero,
      ripple, flickr or custom(abc...xyz)] */
    alphabet: Alphabet,

    help: bool
}

This retains the indentation from the multi-line doc comment resulting in misaligned text in --help

Optional arguments:
  -a, --alphabet ALPHABET  Which base58 alphabet to decode/encode with [possible values: bitcoin, monero,
     ripple, flickr or custom(abc...xyz)]

Not obvious how to have required arguments

I've spend about 10 minutes working on a project using Gumdrop, reading the docs, examples etc, but I can't find anywhere saying how to have required arguments, something like #[required].

Add groups and constraints

Hi,

There should be a way to specify various argument grouping and constraints, e.g. "-f implies -a and -b" or "-n, -m, -l are mutually exclusive".

gumdrop_derive does not compile with minimal versions

The crate versions specified in gumdrop_drive's Cargo.toml file are too low. It can't compile when using those versions. To demonstrate, do

$ cargo update -Zminimal-versions
$ cargo check

on any project that uses gumpdrop. It will fail with errors like this:

error[E0599]: no method named `get_ident` found for reference `&syn::Path` in the current scope
    --> /home/somers/.cargo/registry/src/github.com-1ecc6299db9ec823/gumdrop_derive-0.8.0/src/lib.rs:1039:52
     |
1039 |                     Meta::Path(path) => match path.get_ident() {
     |                                                    ^^^^^^^^^ help: there is an associated function with a similar name: `is_ident`

Add validator support

Like:

fn my_func(value: &str) -> Option<u32> {} // or Result

#[options(help = "Sets the target DPI", meta = "DPI", default = "96", validate=my_func)]
dpi: Option<u32>,

Set `no_short` by default

I think no_short should be the default. Not only because short options are a scarce resource, but also for forwards compatibility:

  1. It's hard to keep track of which short options are used and what aliases are left. I.e. when you want to add a very important short option in future.
  2. It's too easy to move fields in a struct when refactoring, and forget that their shortcuts are swapped now.
  3. Also, many options don't even need a short option at all. It's common practice to have only long form for majority of options.

I know it's not backward compatible. But I always feel on minefield when adding an option with autogenerated shortcut. What do you think?

Formatting with cargo fmt

Keeping the source formatted automatically allows anyone that wants to contribute to just format the source automatically for their changes, without introducing a large delta in existing code.

For any preference in formatting style that differs from the default, rustfmt supports configuration via rustfmt.toml.

While a formatting PR is easy, to keep code formatted in the future, a CI item can be added.

Documentation for `default` option is confusing

Currently, if I add a default = "8000" to my port: Option<u16> without removing the Option, it gives the following error message.

the trait `std::str::FromStr` is not implemented for `std::option::Option<u16>`

I found this extremely confusing because I didn't try compiling it before adding the default and the documentation doesn't mention that adding default will narrow the set of valid type signatures, and the Option<i32> example from the docs was also breaking.

(I went in circles double-checking these examples for 15 minutes and looking at the FromStr API docs before it occurred to me that maybe default altered the set of valid types.)

The documentation for default should be amended to mention this.

Use Option for optional arguments

This would potentially be a breaking API change, but I'd like to suggest that the Option type be used for optional arguments.

Currently, Option seems to be superfluous, as arguments are still optional unless the "required" meta flag is set.

In addition, the following scenario seems to be unachievable with the current implementation:

  • an optional argument that optionally accepts a value
  • has a default value when not set

As an example, let's say a command-line tool normally has output that is unsorted. If you pass the -s argument in, then output should become sorted in some default way (e.g. alphabetically). Additionally, if you pass a value to the -s argument, you can specify the way in which the sort occurs (e.g. "-sa" for alphabetical, "-sn" for numerical).

In my case, the "principal of least surprise" led me to think that the following might achieve that result:

#[derive(Debug, Options)]
struct GramsOptions {
    #[options(help = "sort tallied output: a=alphabetic [DEFAULT], n=numeric")]
    sort: Option<String>,
}

I expected I might be able to parse this as follows:

let sort: Option<Sort> = match opts.sort.as_ref().map(|s| &s[..]) {
    Some("a") => Some(Sort::Alphabetic),
    Some("n") => Some(Sort::Numeric),
    None => Some(Sort::Alphabetic),
};

Deeper integration of `--help`, especially for printing subcommand help

I noticed the subcommands example talks about using a dedicated help subcommand, and it helps that the command_usage API is tailored for it. However I also want to support --help for every subcommand to do the same thing which unfortunately requires lots of verbose code:

Toggle
extern crate gumdrop;
#[macro_use] extern crate gumdrop_derive;

use std::io::Write;
use gumdrop::Options;

#[derive(Debug, Default, Options)]
struct MainOptions {
	#[options(help = "Print the help message")]
	help: bool,

	#[options(command)]
	subcommand: Option<SubCommand>,
}

#[derive(Debug, Options)]
enum SubCommand {
	#[options(help = "Does foo")]
	Foo(FooOptions),

	#[options(help = "Does bar")]
	Bar(BarOptions),
}

#[derive(Debug, Default, Options)]
struct FooOptions {
	#[options(help = "Print the help message")]
	help: bool,

	#[options(help = "The thing to foo")]
	thing: String,
}

#[derive(Debug, Default, Options)]
struct BarOptions {
	#[options(help = "Print the help message")]
	help: bool,

	#[options(help = "The thing to bar")]
	thing: String,
}

fn main() {
	let args: Vec<_> = std::env::args().collect();
	let options: MainOptions = gumdrop::parse_args_default(&args[1..]).unwrap_or_else(|err| {
		// Invalid args
		writeln!(std::io::stderr(), "{}", err);
		print_usage(std::io::stderr());
		std::process::exit(1);
	});

	if options.help {
		// Explicitly asked for help
		print_usage(std::io::stdout());
		return;
	}

	let subcommand = options.subcommand.unwrap_or_else(|| {
		// Did not provide subcommand (required)
		print_usage(std::io::stderr());
		std::process::exit(1);
	});

	let subcommand_usage = match subcommand {
		SubCommand::Foo(FooOptions { help: true, .. }) => Some(("foo", FooOptions::usage())),
		SubCommand::Bar(BarOptions { help: true, .. }) => Some(("bar", BarOptions::usage())),
		_ => None,
	};

	if let Some((subcommand_name, subcommand_usage)) = subcommand_usage {
		// Explicitly asked for subcommand help
		print_subcommand_usage(std::io::stdout(), subcommand_name, subcommand_usage);
		return;
	}

	// Run the subcommand
	match subcommand {
		SubCommand::Foo(FooOptions { thing, .. }) => println!("Foo the thing {}", thing),
		SubCommand::Bar(BarOptions { thing, .. }) => {
			if thing.is_empty() {
				writeln!(std::io::stderr(), "Invalid thing");
				print_subcommand_usage(std::io::stderr(), "bar", BarOptions::usage());
				std::process::exit(1);
			}
			println!("Bar the thing {}", thing)
		},
	}
}

fn print_usage<W: Write>(mut w: W) {
	writeln!(w, "{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
	writeln!(w, "{}", env!("CARGO_PKG_AUTHORS"));
	writeln!(w, "{}", env!("CARGO_PKG_DESCRIPTION"));
	writeln!(w);
	writeln!(w, "USAGE:");
	writeln!(w, "  {} <SUBCOMMAND>", env!("CARGO_PKG_NAME"));
	writeln!(w);
	writeln!(w, "FLAGS");
	writeln!(w, "{}", MainOptions::usage());
	writeln!(w);
	writeln!(w, "SUBCOMMANDS:");
	writeln!(w, "{}", SubCommand::usage());
}

fn print_subcommand_usage<W: Write>(mut w: W, subcommand_name: &'static str, subcommand_usage: &'static str) {
	writeln!(w, "USAGE:");
	writeln!(w, "  {} {} [ARGUMENTS]", env!("CARGO_PKG_NAME"), subcommand_name);
	writeln!(w);
	writeln!(w, "FLAGS:");
	writeln!(w, "{}", subcommand_usage);
}

The expectations are that:

  1. cargo run -- should print the top-level usage text, and exit with 1.

  2. cargo run -- --help should print the top-level usage text, and exit with 0.

  3. cargo run -- foo --help should print the usage text for the foo subcommand, and exit with 0.

  4. cargo run -- bar should get an Invalid thing error, print the usage text for the bar subcommand, and exit with 1.

  5. cargo run -- baz should get an unrecognized command error, print the top-level usage text, and exit with 1.

There are two bad things about this code:

  1. I have to see if the user asked for subcommand help by matching over every subcommand variant and extracting its help field.

  2. For printing the usage of a matched subcommand, I want to print the name of the matched subcommand, but I can't get it. Instead I have to repeat it myself (the "foo" in Some(("foo", FooOptions::usage()))). gumdrop already knows the subcommand name since it matched on it in SubCommand::parse_command, but it doesn't give a way to get it from the parsed value.

It would be nice if:

  1. the struct member holding the subcommand enum (MainOptions::subcommand in the above example) could also know the name of the subcommand it has matched. Perhaps gumdrop could see if it's Option<SubCommand> or Option<(SubCommand, &'static str)>, and additionally put the name in the latter case.

  2. there was some built-in handling for detecting the presence of --help and determining whose usage text should be printed (top-level or a subcommand). I'm not asking for something that actually prints the usage, ie, I'm not asking for a replacement for the print_usage and print_subcommand_usage functions. Rather I'm asking for a replacement for the match block that checks for help: true in every subcommand.

So all together, it could be used like this:

#[derive(Debug, Default, Options)]
struct MainOptions {
	#[options(help = "Print the help message")]
	help: bool,

	#[options(command)]
	subcommand: Option<(SubCommand, &'static str)>, // Tuple here
}

and

if options.help_requested() { // New function on gumdrop::Options
	// Explicitly asked for help
	print_usage(std::io::stdout());
	return;
}

let (subcommand, subcommand_name) = options.subcommand.unwrap_or_else(|| {
	// Did not provide subcommand (required)
	print_usage(std::io::stderr());
	std::process::exit(1);
});

if subcommand.help_requested() { // New function on gumdrop::Options
	// Explicitly asked for subcommand help
	print_subcommand_usage(std::io::stdout(), subcommand_name, subcommand.command_usage(subcommand_name).unwrap());
	return;
}

where the first fn help_requested(&self) -> bool function checks for self.help == true and the second fn help_requested(&self) -> bool function checks for help == true in any of the variants of the subcommand.

where does this 'all caps LIST-IMPORTS' come from?

With the source below:

use gumdrop::Options;
use std::{env, fs, process};

#[derive(Debug, Options)]
struct Args {
    #[options(help = "Prints the version", short = "v", long = "version")]
    version: bool,

    #[options(help = "Calls the list_imports function with a filename", short = "l", long = "list-imports")]
    list_imports: Option<String>,

    #[options(help = "Updates DLL bindings for <from> so it points to <to>", short = "s", long = "set-import")]
    set_import: bool,

    #[options(free)]
    free_args: Vec<String>,

    #[options(help = "Print this help message and exit", short = "h")]
    help: bool,
}

fn main() {
    let args = Args::parse_args_default_or_exit();

    if args.help {
        println!("{}", Args::usage());
        return;
    }

    if args.version {
        println!("fixPath version 1.0"); // FIXME read from cargo.toml
    } else if let Some(filename) = args.list_imports {
        println!("{}", filename);
    } else if args.set_import {
        if args.free_args.len() == 3 {
            println!(
                "set-import: {}, {}, {}",
                args.free_args[0], args.free_args[1], args.free_args[2]
            );
        } else {
            eprintln!("Error: --set-import requires exactly 3 arguments.");
        }
    } else {
        eprintln!("Error: one of --version, --list-imports or --set-import must be provided.");
        println!("{}", Args::usage());
        process::exit(1);
    }
}

why does the text LIST-IMPORTS in call caps appear?!

.\fixPath.exe -h
Usage: C:\Users\joschie\Desktop\Projects\fixPath\target\debug\fixPath.exe [OPTIONS]

Positional arguments:
  free_args

Optional arguments:
  -v, --version     Prints the version
  -l, --list-imports LIST-IMPORTS
                    Prints <file>'s DLL bindings
  -s, --set-import  Updates <file>'s DLL bindings <from> so it points to <to>
  -h, --help        Print this help message and exit

https://replit.com/@qknight/gumdrop-example#src/main.rs

Consider removing syn and proc-macro2

I'm not familiar with procedural macros, but is it possible to depend only on proc-macro? The problem is that proc-macro2 and syn a very slow to build:

> cargo bloat --release --time -j1
Compiling ...

  Time Crate
44.36s syn
21.22s gumdrop_derive
 5.42s proc_macro2
 1.55s quote
 0.48s gumdrop
 0.12s unicode_xid

On the other hand, arguments parsing without macros is too verbose.

Add a 'default' option

Add support for a default value.

#[options(help = "Sets the target DPI", meta = "DPI", default = "96")]
dpi: u32,

If it possible it would be great to set a type instead of a string as a default value.

Print usage on error

Is it possible to use this crate and show the usage information automatically if arguments are missing or parsing fails? This is the default behavior in structopt and clap.

Disable print of env var names - env vars not being parsed

Unsure what my issue is here, but it seems that environment variables are not being parsed for me.

It would also be nice to have an optional argument to pass to parse_args_default_or_exit and similar to disable the printing/parsing of environment variables.

Add a skip or hide property

Would it be possible to add an option to gumdrop_derive that skips one of the struct's fields? Or if not, one that hides it from the help menu?

My motivation is to combine gumdrop with confy on a single struct. Most options should be configurable either from the command line or from the config file, but a few options are only relevant for one or the other. Here's an example of how to use such an option:

#[derive(Debug, Default, Deserialize, Options, Serialize)]
struct Config {
    #[options(help = "print help message")]
    // it makes no sense to set --help in the config file
    #[serde(skip)]
    help: bool,
    /// Thread pool size
    // This one makes sense both both config file and CLI
    #[options(default = "1")]
    threads: i32,
    /// Specify the server's parameters in JSON
    // This field is too complicated for the command-line.  Only enable it in the config file
    #[options(skip)]
    serverspec: Option<String>
}

Provide default help text for --help

If you're already assigning magical behaviour to naming a boolean argument help, it seems like a wart to not include a default help string in that magic behaviour.

Among other reasons, if the help string is provided by default, most users will only need the single help: bool, line for it.

Pass function to default (for string)

I'm trying to use a function called default_config() to provide the default value for an option:

pub fn default_config() -> String {
    option_env!("BIN_DEFAULT_CONFIG_PATH")
        .unwrap_or("/etc/default/path")
        .to_owned()
}

#[derive(Options)]
pub struct FetchOpts {
    #[options(help = "Path to the config file", default = "default_config()")]
    pub config: String,
}

However, that is interpreted as the literal value "default_config()". Passing default = default_config() causes a syntax error panic instead.

Is there a sensible way to set that default value, taking advantage of the help text auto-generation? (If not, I can fall back to the unwrap method, which I was previously using)

Nested types (flatten args)

It would be really nice if the following worked, in order to enable re-use of options between multiple commands:

#[derive(Options)]
struct CommonOpts {
  foo: bool,
}

#[derive(Options)]
struct Opts {
  bar: bool,

  #[options(flatten)]
  common: CommonOpts,
}

// call using `program --foo --bar`

Confusing validation message for free args

Given the following:

fn parse_username(input: &str) -> Result<String, String> {
  // always fails
  Err("Username is invalid!")
}

#[derive(Options)]
pub struct CliOptions {
  #[options(free, parse(try_from_str = "parse_username"))]
  pub username: String,
}

As of commit 121667e, I get the following error message when passing a username (which is designed to fail, here):

[bin_name]: invalid argument to option `free`: Username is invalid!

I attempted to describe it using meta to change the identifier free, but meta and free are mutually exclusive. Is there a way to change free to username, in this scenario?

ErrorKind can't be retrieved

I don't like the style of this crate's error messages ("unexpected free argument" vs "too many arguments") so I wanted to rewrite the error messages myself by catching errors and matching on them. However, once I obtain an Error struct, I can't actually extract the kind out of it because it's private and there's no getter!

:(

tuples

Is there a possibility to support something like this:

    #[derive(Debug, Default, Options)]
    struct CreateOptions {
        #[options(no_short, help = "some parameter")]
        test_parameter: Vec<(String,String)>,
    }

so you can run commands like this:

./mybinary --test-parameter VARIABLE VALUE --test-parameter ANOTHERVARIABLE ANOTHERVALUE

That would be nice to have

Display positional arguments in 'usage' line.

Right now, I have the following struct:

#[derive(Options)]
struct Arguments {

    /// print help message
    help: bool,    

    #[options(free,required)]
    /// The file to extract data from
    source: PathBuf,

    #[options(free,required)]
    /// The file to insert the data into
    target: PathBuf,
}

When I call the program with '--help', I get the following usage:

Usage: clitool [OPTIONS]

Positional arguments:
  source      The file to extract data from
  target      The file to insert the data into

Optional arguments:
  -h, --help  print help message

In almost every other command line tool on my system, that first line of Usage would be something like: Usage: clitool [OPTIONS] SOURCE TARGET.

Right now I have to duplicate the code from parse_args_or_exit in order to add this.

It would be nice if gumdrop did this automatically, or at least allowed me to customize the usage line.

Required arguments

Now everything is optional, is there a possibility to make a flag required ?

for example

./myapp --server myapp.com

and when --server flag is not passed the app throws an error.

or is this already possible and I'm just looking over it ?

I know I can go manually over all the flags and throw an error, but I wonder if there is an automatic way

Nested subcommand support with `--help`

Using gumpdrop 0.7.0 with #[derive(Options)] does not support nested subcommands in the built-in help output.

For an example program, here's myprogram which allows users to manage user accounts and organizations with a command structure similar to this:

$ mycommand account new
$ mycommand account update --name alice
$ mycommand org add-member

etc...

The problem is that the behavior of --help seems unaware of subcommands. Here's an example main demonstrating the behavior for the above command:

use gumdrop::Options;

// Define options for the program.
#[derive(Debug, Options)]
pub struct MainOptions {
    #[options(help = "print help message")]
    help: bool,

    #[options(command)]
    command: Option<Command>,
}

#[derive(Debug, Options)]
pub enum Command {
    #[options(help = "manage an account")]
    Account(AccountOptions),

    #[options(help = "manage an organization")]
    Org(OrgOptions),
}

#[derive(Debug, Options)]
pub struct AccountOptions {
    #[options(help = "print help message")]
    help: bool,

    #[options(command)]
    command: Option<AccountCommand>,
}

#[derive(Debug, Options)]
pub enum AccountCommand {
    #[options(help = "create a new account")]
    New(AccountNewOptions),

    #[options(help = "update account details")]
    Update(AccountUpdateOptions),
}

#[derive(Debug, Options)]
pub struct AccountNewOptions {
    #[options(help = "print help message")]
    help: bool,
}

#[derive(Debug, Options)]
pub struct AccountUpdateOptions {
    #[options(help = "print help message")]
    help: bool,

    #[options(help = "set account name")]
    name: String,
}

// This is just empty scaffolding for now:
#[derive(Debug, Options)]
pub struct OrgOptions {}

fn main() {
    let opts = MainOptions::parse_args_default_or_exit();

    println!("{:#?}", opts);
}

The following snippets show the behavior of --help along with desired changes.

$ mycommand --help
Usage: mycommand [OPTIONS]

Optional arguments:
  -h, --help  print help message

Available commands:

  account  manage an account
  org      manage an organization

This output works well and supports the top-level subcommands well.

$ mycommand --help account
Usage: mycommand account [OPTIONS]

Optional arguments:
  -h, --help  print help message

This output shows the right commandline to include the account command, but it doesn't show the account's subcommands new and update.

$ mycommand account --help
Usage: mycommand account [OPTIONS]

Optional arguments:
  -h, --help  print help message

This behavior is identical to --help account which is my desired behavior, based on a common pattern with cli tools. Fixing the bug in the --help account approach should maintain this synonymous behavior for this case.

$ mycommand account --help new
Usage: mycommand account [OPTIONS]

Optional arguments:
  -h, --help  print help message

This shows the same output as without the new. Instead I request that it shows the full command as mycommand account new [option] plus the new specific options.

$ mycommand account new --help
Usage: mycommand account [OPTIONS]

Optional arguments:
  -h, --help  print help message

Just as with the account --help and --help account cases, this case should be synonymous with the previous case to account --help new.

Finally, this request should apply to an arbitrary depth of subcommands. Is this request coherent and possible? Are there any problems with this design or approach?

Why I can't describe `free` arguments?

Structure is:

#[derive(Options, Debug, Default)]
#[options(no_short)]
struct MyOptions {
    #[options(help="Print help message and exit")]
    help: bool,
    #[options(free, help="filename")]
    filenames: Vec<String>,
}

Error is:

  = help: message: `free` and `help` are mutually exclusive

What's wrong with describing positional arguments? Use case is kinda like in ls command. Maybe there is other way to implement positional arguments instead of free? (which is a weird name for the task indeed).

Required free argument error is not very helpful

With a struct like

#[derive(Debug, Options)]
pub(crate) struct RawConfig {
    #[options(free, required, help = "File to run")]
    pub file_to_run: String,
    ....
    }

When run without any free parameters I get:
missing required free argument

Where I'd hope to get something like missing required argument file_to_run or such. I think users of this application will not understand what the free argument means, probably will try to call with a --free option or something.

`parse_args_or_exit` function

It would be nice to have a single function which does the following:

  1. Checks arguments
  2. Prints help if --help is specified
  3. Exits with 0 if help is specified or error code 2 if there is an error

I think this is important because even if front page examples there there are few mistakes: (1) no error code returned, (2) error message is printed to stdout not stderr.

What do you think? Is there any limitations of help that could be generated by such function? I.e. a problem with subcommands or something?

Can't parse a Vec<String>

fn parse_languages(s: &str) -> Result<Vec<String>, &'static str> {
    let mut langs = Vec::new();
    for lang in s.split(',') {
        langs.push(lang.trim().to_string());
    }

    Ok(langs)
}

// ...

#[options(no_short, meta = "LANG", default = "en", parse(try_from_str = "parse_languages"))]
languages: Vec<String>,
error[E0308]: try expression alternatives have incompatible types
  --> src/main.rs:81:17
   |
81 | #[derive(Debug, Options)]
   |                 ^^^^^^^
   |                 |
   |                 expected struct `std::string::String`, found struct `std::vec::Vec`
   |                 help: try wrapping with a success variant: `Ok(Options)`
   |
   = note: expected type `std::string::String`
              found type `std::vec::Vec<std::string::String>`

Verbose message for screen readers like Orca/NVDA

Hi.

Is there any option to remove the command line from the error messages? For example, supposing we passa an invalid argument, it is reported like this:

$ ./some/portable/media/test -d
./some/portable/media/test: unrecognized option -d

So, if you are using a screen reader like Orca or NVDA, you will hear "dot" "bar" "some" "bar" "portable" "bar" "media" "bar" "test" and finally hear the error message "unrecognized option -d".

cheers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.