{"id":13595007,"url":"https://github.com/blyxxyz/lexopt","last_synced_at":"2026-03-01T00:03:04.611Z","repository":{"id":39514023,"uuid":"383874478","full_name":"blyxxyz/lexopt","owner":"blyxxyz","description":"Minimalist pedantic command line parser","archived":false,"fork":false,"pushed_at":"2025-03-31T12:42:10.000Z","size":178,"stargazers_count":335,"open_issues_count":4,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-08T14:18:55.147Z","etag":null,"topics":["argument-parser","command-line","getopt","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blyxxyz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-07-07T17:21:56.000Z","updated_at":"2025-05-06T17:31:10.000Z","dependencies_parsed_at":"2024-06-18T22:33:17.068Z","dependency_job_id":"a90ad335-5f79-4f92-9980-e062863d9eed","html_url":"https://github.com/blyxxyz/lexopt","commit_stats":{"total_commits":140,"total_committers":1,"mean_commits":140.0,"dds":0.0,"last_synced_commit":"f233d7486cdad90cce83fb57919432842a592d2f"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blyxxyz%2Flexopt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blyxxyz%2Flexopt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blyxxyz%2Flexopt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blyxxyz%2Flexopt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blyxxyz","download_url":"https://codeload.github.com/blyxxyz/lexopt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254179897,"owners_count":22027883,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argument-parser","command-line","getopt","rust"],"created_at":"2024-08-01T16:01:42.303Z","updated_at":"2026-03-01T00:02:59.574Z","avatar_url":"https://github.com/blyxxyz.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Lexopt\n\n[![Crates.io](https://img.shields.io/crates/v/lexopt.svg)](https://crates.io/crates/lexopt)\n[![API reference](https://docs.rs/lexopt/badge.svg)](https://docs.rs/lexopt/)\n[![MSRV](https://img.shields.io/badge/MSRV-1.31-blue)](https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html)\n[![CI](https://img.shields.io/github/actions/workflow/status/blyxxyz/lexopt/ci.yaml?branch=master)](https://github.com/blyxxyz/lexopt/actions)\n\nLexopt is an argument parser for Rust. It tries to have the simplest possible design that's still correct. It's so simple that it's a bit tedious to use.\n\nLexopt is:\n- Small: one file, no dependencies, no macros. Easy to audit or vendor.\n- Correct: standard conventions are supported and ambiguity is avoided. Tested and fuzzed.\n- Pedantic: arguments are returned as [`OsString`](https://doc.rust-lang.org/std/ffi/struct.OsString.html)s, forcing you to convert them explicitly. This lets you handle badly-encoded filenames.\n- Imperative: options are returned as they are found, nothing is declared ahead of time.\n- Minimalist: only basic functionality is provided.\n- Unhelpful: there is no help generation and error messages often lack context.\n\n## Example\n```rust\nstruct Args {\n    thing: String,\n    number: u32,\n    shout: bool,\n}\n\nfn parse_args() -\u003e Result\u003cArgs, lexopt::Error\u003e {\n    use lexopt::prelude::*;\n\n    let mut thing = None;\n    let mut number = 1;\n    let mut shout = false;\n    let mut parser = lexopt::Parser::from_env();\n    while let Some(arg) = parser.next()? {\n        match arg {\n            Short('n') | Long(\"number\") =\u003e {\n                number = parser.value()?.parse()?;\n            }\n            Long(\"shout\") =\u003e {\n                shout = true;\n            }\n            Value(val) if thing.is_none() =\u003e {\n                thing = Some(val.string()?);\n            }\n            Long(\"help\") =\u003e {\n                println!(\"Usage: hello [-n|--number=NUM] [--shout] THING\");\n                std::process::exit(0);\n            }\n            _ =\u003e return Err(arg.unexpected()),\n        }\n    }\n\n    Ok(Args {\n        thing: thing.ok_or(\"missing argument THING\")?,\n        number,\n        shout,\n    })\n}\n\nfn main() -\u003e Result\u003c(), lexopt::Error\u003e {\n    let args = parse_args()?;\n    let mut message = format!(\"Hello {}\", args.thing);\n    if args.shout {\n        message = message.to_uppercase();\n    }\n    for _ in 0..args.number {\n        println!(\"{}\", message);\n    }\n    Ok(())\n}\n```\n\nLet's walk through this:\n- We start parsing with `Parser::from_env()`.\n- We call `parser.next()` in a loop to get all the arguments until they run out.\n- We match on arguments. `Short` and `Long` indicate an option.\n- To get the value that belongs to an option (like `10` in `-n 10`) we call `parser.value()`.\n  - This returns a standard [`OsString`](https://doc.rust-lang.org/std/ffi/struct.OsString.html).\n    - For convenience, `use lexopt::prelude::*` adds a `.parse()` method, analogous to [the one on `\u0026str`](https://doc.rust-lang.org/std/primitive.str.html#method.parse).\n  - Calling `parser.value()` is how we tell `Parser` that `-n` takes a value at all.\n- `Value` indicates a free-standing argument.\n  - `if thing.is_none()` is a useful pattern for positional arguments. If we already found `thing` we pass it on to another case.\n  - It also contains an `OsString`.\n    - The `.string()` method decodes it into a plain `String`.\n- If we don't know what to do with an argument we use `return Err(arg.unexpected())` to turn it into an error message.\n- Strings can be promoted to errors for custom error messages.\n\nThis covers most of the functionality in the library. Lexopt does very little for you.\n\nFor a larger example with useful patterns, see [`examples/cargo.rs`](examples/cargo.rs).\n\n## Command line syntax\nThe following conventions are supported:\n- Short options (`-q`)\n- Long options (`--verbose`)\n- `--` to mark the end of options\n- `=` to separate options from values (`--option=value`, `-o=value`)\n- Spaces to separate options from values (`--option value`, `-o value`)\n- Unseparated short options (`-ovalue`)\n- Combined short options (`-abc` to mean `-a -b -c`)\n- Options with optional arguments (like GNU sed's `-i`, which can be used standalone or as `-iSUFFIX`) ([`Parser::optional_value()`](https://docs.rs/lexopt/latest/lexopt/struct.Parser.html#method.optional_value))\n- Options with multiple arguments ([`Parser::values()`](https://docs.rs/lexopt/latest/lexopt/struct.Parser.html#method.values))\n\nThese are not supported out of the box:\n- Single-dash long options (like find's `-name`)\n- Abbreviated long options (GNU's getopt lets you write `--num` instead of `--number` if it can be expanded unambiguously)\n\n[`Parser::raw_args()`](https://docs.rs/lexopt/latest/lexopt/struct.Parser.html#method.raw_args) and [`Parser::try_raw_args()`](https://docs.rs/lexopt/latest/lexopt/struct.Parser.html#method.try_raw_args) provide an escape hatch for consuming the original command line. This can be used for custom syntax, like treating `-123` as a number instead of a string of options. See [`examples/nonstandard.rs`](examples/nonstandard.rs) for an example of this.\n\n## Unicode\nThis library supports unicode while tolerating non-unicode arguments.\n\nShort options may be unicode, but only a single codepoint (a `char`).\n\nOptions can be combined with non-unicode arguments. That is, `--option=���` will not cause an error or mangle the value.\n\nOptions themselves are patched as by [`String::from_utf8_lossy`](https://doc.rust-lang.org/std/string/struct.String.html#method.from_utf8_lossy) if they're not valid unicode. That typically means you'll raise an error later when they're not recognized.\n\n## Why?\nFor a particular application I was looking for a small parser that's pedantically correct. There are other compact argument parsing libraries, but I couldn't find one that handled `OsString`s and implemented all the fiddly details of the argument syntax faithfully.\n\nThis library may also be useful if a lot of control is desired, like when the exact argument order matters or not all options are known ahead of time. It could be considered more of a lexer than a parser.\n\n## Why not?\nThis library may not be worth using if:\n- You don't care about non-unicode arguments\n- You don't care about exact compliance and correctness\n- You don't care about code size\n- You do care about great error messages\n- You hate boilerplate\n\n## See also\n- [Collected benchmarks of argument parsing crates](https://github.com/rosetta-rs/argparse-rosetta-rs).\n- libc's [`getopt`](https://en.wikipedia.org/wiki/Getopt#Examples).\n- Plan 9's [*arg(3)* macros](https://9fans.github.io/plan9port/man/man3/arg.html).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblyxxyz%2Flexopt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblyxxyz%2Flexopt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblyxxyz%2Flexopt/lists"}