Struct lexopt::Parser

source ·
pub struct Parser { /* private fields */ }
Expand description

A parser for command line arguments.

Implementations§

Get the next option or positional argument.

A return value of Ok(None) means the command line has been exhausted.

Options that are not valid unicode are transformed with replacement characters as by String::from_utf8_lossy.

Errors

Error::UnexpectedValue is returned if the last option had a value that hasn’t been consumed, as in --option=value or -o=value.

It’s possible to continue parsing after an error (but this is rarely useful).

Examples found in repository?
examples/posixly_correct.rs (line 16)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut parser = lexopt::Parser::from_env();
    let mut free = Vec::new();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('n') | Long("number") => {
                let num: u16 = parser.value()?.parse()?;
                println!("Got number {}", num);
            }
            Long("shout") => {
                println!("Got --shout");
            }
            Value(val) => {
                free.push(val);
                free.extend(parser.raw_args()?);
            }
            _ => return Err(arg.unexpected()),
        }
    }
    println!("Got free args {:?}", free);
    Ok(())
}
More examples
Hide additional examples
examples/hello.rs (line 14)
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn parse_args() -> Result<Args, lexopt::Error> {
    use lexopt::prelude::*;

    let mut thing = None;
    let mut number = 1;
    let mut shout = false;
    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('n') | Long("number") => {
                number = parser.value()?.parse()?;
            }
            Long("shout") => {
                shout = true;
            }
            Value(val) if thing.is_none() => {
                thing = Some(val.string()?);
            }
            Long("help") => {
                println!("Usage: hello [-n|--number=NUM] [--shout] THING");
                std::process::exit(0);
            }
            _ => return Err(arg.unexpected()),
        }
    }

    Ok(Args {
        thing: thing.ok_or("missing argument THING")?,
        number,
        shout,
    })
}
examples/nonstandard.rs (line 27)
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut parser = lexopt::Parser::from_env();
    loop {
        if let Some(num) = parse_dashnum(&mut parser) {
            println!("Got number {}", num);
        } else if let Some(arg) = parser.next()? {
            match arg {
                Short('f') | Long("follow") => {
                    println!("Got --follow");
                }
                Short('n') | Long("number") => {
                    let num: u64 = parser.value()?.parse()?;
                    println!("Got number {}", num);
                }
                Value(path) => {
                    let path = PathBuf::from(path);
                    println!("Got file {}", path.display());
                }
                _ => return Err(arg.unexpected()),
            }
        } else {
            break;
        }
    }

    Ok(())
}
examples/pico_test_app.rs (line 58)
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
fn parse_args() -> Result<AppArgs, lexopt::Error> {
    use lexopt::prelude::*;

    let mut number = None;
    let mut opt_number = None;
    let mut width = 10;
    let mut input = None;

    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('h') | Long("help") => {
                print!("{}", HELP);
                std::process::exit(0);
            }
            Long("number") => number = Some(parser.value()?.parse()?),
            Long("opt-number") => opt_number = Some(parser.value()?.parse()?),
            Long("width") => width = parser.value()?.parse_with(parse_width)?,
            Value(path) if input.is_none() => input = Some(path.into()),
            _ => return Err(arg.unexpected()),
        }
    }
    Ok(AppArgs {
        number: number.ok_or("missing required option --number")?,
        opt_number,
        width,
        input: input.ok_or("missing required argument INPUT")?,
    })
}
examples/cargo.rs (line 21)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut settings = GlobalSettings {
        toolchain: "stable".to_owned(),
        color: Color::Auto,
        offline: false,
        quiet: false,
        verbose: false,
    };

    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Long("color") => {
                settings.color = parser.value()?.parse()?;
            }
            Long("offline") => {
                settings.offline = true;
            }
            Long("quiet") => {
                settings.quiet = true;
                settings.verbose = false;
            }
            Long("verbose") => {
                settings.verbose = true;
                settings.quiet = false;
            }
            Long("help") => {
                println!("{}", HELP);
                std::process::exit(0);
            }
            Value(value) => {
                let value = value.string()?;
                match value.as_str() {
                    value if value.starts_with('+') => {
                        settings.toolchain = value[1..].to_owned();
                    }
                    "install" => {
                        return install(settings, parser);
                    }
                    value => {
                        return Err(format!("unknown subcommand '{}'", value).into());
                    }
                }
            }
            _ => return Err(arg.unexpected()),
        }
    }

    println!("{}", HELP);
    Ok(())
}

#[derive(Debug)]
struct GlobalSettings {
    toolchain: String,
    color: Color,
    offline: bool,
    quiet: bool,
    verbose: bool,
}

fn install(settings: GlobalSettings, mut parser: lexopt::Parser) -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut package: Option<String> = None;
    let mut root: Option<PathBuf> = None;
    let mut jobs: u16 = get_no_of_cpus();

    while let Some(arg) = parser.next()? {
        match arg {
            Value(value) if package.is_none() => {
                package = Some(value.string()?);
            }
            Long("root") => {
                root = Some(parser.value()?.into());
            }
            Short('j') | Long("jobs") => {
                jobs = parser.value()?.parse()?;
            }
            Long("help") => {
                println!("cargo install [OPTIONS] CRATE");
                std::process::exit(0);
            }
            _ => return Err(arg.unexpected()),
        }
    }

    println!("Settings: {:#?}", settings);
    println!(
        "Installing {} into {:?} with {} jobs",
        package.ok_or("missing CRATE argument")?,
        root,
        jobs
    );

    Ok(())
}

Get a value for an option.

This function should normally be called right after seeing an option that expects a value, with positional arguments being collected using next().

A value is collected even if it looks like an option (i.e., starts with -).

Errors

An Error::MissingValue is returned if the end of the command line is reached.

Examples found in repository?
examples/posixly_correct.rs (line 19)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut parser = lexopt::Parser::from_env();
    let mut free = Vec::new();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('n') | Long("number") => {
                let num: u16 = parser.value()?.parse()?;
                println!("Got number {}", num);
            }
            Long("shout") => {
                println!("Got --shout");
            }
            Value(val) => {
                free.push(val);
                free.extend(parser.raw_args()?);
            }
            _ => return Err(arg.unexpected()),
        }
    }
    println!("Got free args {:?}", free);
    Ok(())
}
More examples
Hide additional examples
examples/hello.rs (line 17)
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn parse_args() -> Result<Args, lexopt::Error> {
    use lexopt::prelude::*;

    let mut thing = None;
    let mut number = 1;
    let mut shout = false;
    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('n') | Long("number") => {
                number = parser.value()?.parse()?;
            }
            Long("shout") => {
                shout = true;
            }
            Value(val) if thing.is_none() => {
                thing = Some(val.string()?);
            }
            Long("help") => {
                println!("Usage: hello [-n|--number=NUM] [--shout] THING");
                std::process::exit(0);
            }
            _ => return Err(arg.unexpected()),
        }
    }

    Ok(Args {
        thing: thing.ok_or("missing argument THING")?,
        number,
        shout,
    })
}
examples/nonstandard.rs (line 33)
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut parser = lexopt::Parser::from_env();
    loop {
        if let Some(num) = parse_dashnum(&mut parser) {
            println!("Got number {}", num);
        } else if let Some(arg) = parser.next()? {
            match arg {
                Short('f') | Long("follow") => {
                    println!("Got --follow");
                }
                Short('n') | Long("number") => {
                    let num: u64 = parser.value()?.parse()?;
                    println!("Got number {}", num);
                }
                Value(path) => {
                    let path = PathBuf::from(path);
                    println!("Got file {}", path.display());
                }
                _ => return Err(arg.unexpected()),
            }
        } else {
            break;
        }
    }

    Ok(())
}
examples/pico_test_app.rs (line 64)
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
fn parse_args() -> Result<AppArgs, lexopt::Error> {
    use lexopt::prelude::*;

    let mut number = None;
    let mut opt_number = None;
    let mut width = 10;
    let mut input = None;

    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('h') | Long("help") => {
                print!("{}", HELP);
                std::process::exit(0);
            }
            Long("number") => number = Some(parser.value()?.parse()?),
            Long("opt-number") => opt_number = Some(parser.value()?.parse()?),
            Long("width") => width = parser.value()?.parse_with(parse_width)?,
            Value(path) if input.is_none() => input = Some(path.into()),
            _ => return Err(arg.unexpected()),
        }
    }
    Ok(AppArgs {
        number: number.ok_or("missing required option --number")?,
        opt_number,
        width,
        input: input.ok_or("missing required argument INPUT")?,
    })
}
examples/cargo.rs (line 24)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut settings = GlobalSettings {
        toolchain: "stable".to_owned(),
        color: Color::Auto,
        offline: false,
        quiet: false,
        verbose: false,
    };

    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Long("color") => {
                settings.color = parser.value()?.parse()?;
            }
            Long("offline") => {
                settings.offline = true;
            }
            Long("quiet") => {
                settings.quiet = true;
                settings.verbose = false;
            }
            Long("verbose") => {
                settings.verbose = true;
                settings.quiet = false;
            }
            Long("help") => {
                println!("{}", HELP);
                std::process::exit(0);
            }
            Value(value) => {
                let value = value.string()?;
                match value.as_str() {
                    value if value.starts_with('+') => {
                        settings.toolchain = value[1..].to_owned();
                    }
                    "install" => {
                        return install(settings, parser);
                    }
                    value => {
                        return Err(format!("unknown subcommand '{}'", value).into());
                    }
                }
            }
            _ => return Err(arg.unexpected()),
        }
    }

    println!("{}", HELP);
    Ok(())
}

#[derive(Debug)]
struct GlobalSettings {
    toolchain: String,
    color: Color,
    offline: bool,
    quiet: bool,
    verbose: bool,
}

fn install(settings: GlobalSettings, mut parser: lexopt::Parser) -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut package: Option<String> = None;
    let mut root: Option<PathBuf> = None;
    let mut jobs: u16 = get_no_of_cpus();

    while let Some(arg) = parser.next()? {
        match arg {
            Value(value) if package.is_none() => {
                package = Some(value.string()?);
            }
            Long("root") => {
                root = Some(parser.value()?.into());
            }
            Short('j') | Long("jobs") => {
                jobs = parser.value()?.parse()?;
            }
            Long("help") => {
                println!("cargo install [OPTIONS] CRATE");
                std::process::exit(0);
            }
            _ => return Err(arg.unexpected()),
        }
    }

    println!("Settings: {:#?}", settings);
    println!(
        "Installing {} into {:?} with {} jobs",
        package.ok_or("missing CRATE argument")?,
        root,
        jobs
    );

    Ok(())
}

Gather multiple values for an option.

This is used for options that take multiple arguments, such as a --command flag that’s invoked as app --command echo 'Hello world'.

It will gather arguments until another option is found, or -- is found, or the end of the command line is reached. This differs from .value(), which takes a value even if it looks like an option.

An equals sign (=) will limit this to a single value. That means -a=b c and --opt=b c will only yield "b" while -a b c, -ab c and --opt b c will yield "b", "c".

Errors

If not at least one value is found then Error::MissingValue is returned.

Example
let arguments: Vec<OsString> = parser.values()?.collect();
let at_most_three_files: Vec<PathBuf> = parser.values()?.take(3).map(Into::into).collect();
for value in parser.values()? {
    // ...
}

Take raw arguments from the original command line.

This returns an iterator of OsStrings. Any arguments that are not consumed are kept, so you can continue parsing after you’re done with the iterator.

To inspect an argument without consuming it, use RawArgs::peek or RawArgs::as_slice.

Errors

Returns an Error::UnexpectedValue if the last option had a left-over argument, as in --option=value, -ovalue, or if it was midway through an option chain, as in -abc. The iterator only yields whole arguments. To avoid this, use try_raw_args().

After this error the method is guaranteed to succeed, as it consumes the rest of the argument.

Example

As soon as a free-standing argument is found, consume the other arguments as-is, and build them into a command.

Value(prog) => {
    let args: Vec<_> = parser.raw_args()?.collect();
    let command = std::process::Command::new(prog).args(args);
}
Examples found in repository?
examples/posixly_correct.rs (line 27)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut parser = lexopt::Parser::from_env();
    let mut free = Vec::new();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('n') | Long("number") => {
                let num: u16 = parser.value()?.parse()?;
                println!("Got number {}", num);
            }
            Long("shout") => {
                println!("Got --shout");
            }
            Value(val) => {
                free.push(val);
                free.extend(parser.raw_args()?);
            }
            _ => return Err(arg.unexpected()),
        }
    }
    println!("Got free args {:?}", free);
    Ok(())
}

Take raw arguments from the original command line, if the current argument has finished processing.

Unlike raw_args() this does not consume any value in case of a left-over argument. This makes it safe to call at any time.

It returns None exactly when optional_value() would return Some.

Note: If no arguments are left then it returns an empty iterator (not None).

Example

Process arguments of the form -123 as numbers. For a complete runnable version of this example, see examples/nonstandard.rs.

fn parse_dashnum(parser: &mut lexopt::Parser) -> Option<u64> {
    let mut raw = parser.try_raw_args()?;
    let arg = raw.peek()?.to_str()?;
    let num = arg.strip_prefix('-')?.parse::<u64>().ok()?;
    raw.next(); // Consume the argument we just parsed
    Some(num)
}

loop {
    if let Some(num) = parse_dashnum(&mut parser) {
        println!("Got number {}", num);
    } else if let Some(arg) = parser.next()? {
        match arg {
            // ...
        }
    } else {
        break;
    }
}
Examples found in repository?
examples/nonstandard.rs (line 13)
12
13
14
15
16
17
18
fn parse_dashnum(parser: &mut lexopt::Parser) -> Option<u64> {
    let mut raw = parser.try_raw_args()?;
    let arg = raw.peek()?.to_str()?;
    let num = arg.strip_prefix('-')?.parse::<u64>().ok()?;
    raw.next(); // Consume the argument we just parsed
    Some(num)
}

The name of the command, as in the zeroth argument of the process.

This is intended for use in messages. If the name is not valid unicode it will be sanitized with replacement characters as by String::from_utf8_lossy.

To get the current executable, use std::env::current_exe.

Example
let mut parser = lexopt::Parser::from_env();
let bin_name = parser.bin_name().unwrap_or("myapp");
println!("{}: Some message", bin_name);

Get a value only if it’s concatenated to an option, as in -ovalue or --option=value or -o=value, but not -o value or --option value.

Create a parser from the environment using std::env::args_os.

This is the usual way to create a Parser.

Examples found in repository?
examples/posixly_correct.rs (line 14)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut parser = lexopt::Parser::from_env();
    let mut free = Vec::new();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('n') | Long("number") => {
                let num: u16 = parser.value()?.parse()?;
                println!("Got number {}", num);
            }
            Long("shout") => {
                println!("Got --shout");
            }
            Value(val) => {
                free.push(val);
                free.extend(parser.raw_args()?);
            }
            _ => return Err(arg.unexpected()),
        }
    }
    println!("Got free args {:?}", free);
    Ok(())
}
More examples
Hide additional examples
examples/hello.rs (line 13)
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn parse_args() -> Result<Args, lexopt::Error> {
    use lexopt::prelude::*;

    let mut thing = None;
    let mut number = 1;
    let mut shout = false;
    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('n') | Long("number") => {
                number = parser.value()?.parse()?;
            }
            Long("shout") => {
                shout = true;
            }
            Value(val) if thing.is_none() => {
                thing = Some(val.string()?);
            }
            Long("help") => {
                println!("Usage: hello [-n|--number=NUM] [--shout] THING");
                std::process::exit(0);
            }
            _ => return Err(arg.unexpected()),
        }
    }

    Ok(Args {
        thing: thing.ok_or("missing argument THING")?,
        number,
        shout,
    })
}
examples/nonstandard.rs (line 23)
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut parser = lexopt::Parser::from_env();
    loop {
        if let Some(num) = parse_dashnum(&mut parser) {
            println!("Got number {}", num);
        } else if let Some(arg) = parser.next()? {
            match arg {
                Short('f') | Long("follow") => {
                    println!("Got --follow");
                }
                Short('n') | Long("number") => {
                    let num: u64 = parser.value()?.parse()?;
                    println!("Got number {}", num);
                }
                Value(path) => {
                    let path = PathBuf::from(path);
                    println!("Got file {}", path.display());
                }
                _ => return Err(arg.unexpected()),
            }
        } else {
            break;
        }
    }

    Ok(())
}
examples/pico_test_app.rs (line 57)
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
fn parse_args() -> Result<AppArgs, lexopt::Error> {
    use lexopt::prelude::*;

    let mut number = None;
    let mut opt_number = None;
    let mut width = 10;
    let mut input = None;

    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('h') | Long("help") => {
                print!("{}", HELP);
                std::process::exit(0);
            }
            Long("number") => number = Some(parser.value()?.parse()?),
            Long("opt-number") => opt_number = Some(parser.value()?.parse()?),
            Long("width") => width = parser.value()?.parse_with(parse_width)?,
            Value(path) if input.is_none() => input = Some(path.into()),
            _ => return Err(arg.unexpected()),
        }
    }
    Ok(AppArgs {
        number: number.ok_or("missing required option --number")?,
        opt_number,
        width,
        input: input.ok_or("missing required argument INPUT")?,
    })
}
examples/cargo.rs (line 20)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
fn main() -> Result<(), lexopt::Error> {
    use lexopt::prelude::*;

    let mut settings = GlobalSettings {
        toolchain: "stable".to_owned(),
        color: Color::Auto,
        offline: false,
        quiet: false,
        verbose: false,
    };

    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Long("color") => {
                settings.color = parser.value()?.parse()?;
            }
            Long("offline") => {
                settings.offline = true;
            }
            Long("quiet") => {
                settings.quiet = true;
                settings.verbose = false;
            }
            Long("verbose") => {
                settings.verbose = true;
                settings.quiet = false;
            }
            Long("help") => {
                println!("{}", HELP);
                std::process::exit(0);
            }
            Value(value) => {
                let value = value.string()?;
                match value.as_str() {
                    value if value.starts_with('+') => {
                        settings.toolchain = value[1..].to_owned();
                    }
                    "install" => {
                        return install(settings, parser);
                    }
                    value => {
                        return Err(format!("unknown subcommand '{}'", value).into());
                    }
                }
            }
            _ => return Err(arg.unexpected()),
        }
    }

    println!("{}", HELP);
    Ok(())
}

Create a parser from an iterator. This is useful for testing among other things.

The first item from the iterator must be the binary name, as from std::env::args_os.

The iterator is consumed immediately.

Example
let mut parser = lexopt::Parser::from_iter(&["myapp", "-n", "10", "./foo.bar"]);

Create a parser from an iterator that does not include the binary name.

The iterator is consumed immediately.

bin_name() will return None. Consider using Parser::from_iter instead.

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.