Skip to content

Commit b892828

Browse files
authored
Merge pull request #82 from epage/split
feat(lexarg): Decouple compatibility surface, allowing for helpers
2 parents fce1950 + 1330cdf commit b892828

19 files changed

Lines changed: 1538 additions & 1010 deletions

File tree

Cargo.lock

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/lexarg-error/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pre-release-replacements = [
2727
default = []
2828

2929
[dependencies]
30-
lexarg = { "version" = "0.1.0", path = "../lexarg" }
30+
lexarg-parser = { "version" = "0.1.0", path = "../lexarg-parser" }
3131

3232
[dev-dependencies]
3333

crates/lexarg-error/examples/hello-error.rs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,57 @@
11
use lexarg_error::ErrorContext;
2-
use lexarg_error::Result;
32

43
struct Args {
54
thing: String,
65
number: u32,
76
shout: bool,
87
}
98

10-
fn parse_args() -> Result<Args> {
9+
fn parse_args() -> Result<Args, String> {
1110
#![allow(clippy::enum_glob_use)]
12-
use lexarg::Arg::*;
11+
use lexarg_parser::Arg::*;
1312

1413
let mut thing = None;
1514
let mut number = 1;
1615
let mut shout = false;
1716
let raw = std::env::args_os().collect::<Vec<_>>();
18-
let mut parser = lexarg::Parser::new(&raw);
17+
let mut parser = lexarg_parser::Parser::new(&raw);
1918
let bin_name = parser
2019
.next_raw()
2120
.expect("nothing parsed yet so no attached lingering")
2221
.expect("always at least one");
2322
while let Some(arg) = parser.next_arg() {
2423
match arg {
2524
Short("n") | Long("number") => {
26-
let value = parser
27-
.next_flag_value()
28-
.ok_or_else(|| ErrorContext::msg("missing required value").within(arg))?;
25+
let value = parser.next_flag_value().ok_or_else(|| {
26+
ErrorContext::msg("missing required value")
27+
.within(arg)
28+
.to_string()
29+
})?;
2930
number = value
3031
.to_str()
3132
.ok_or_else(|| {
3233
ErrorContext::msg("invalid number")
3334
.unexpected(Value(value))
3435
.within(arg)
36+
.to_string()
3537
})?
3638
.parse()
37-
.map_err(|e| ErrorContext::msg(e).unexpected(Value(value)).within(arg))?;
39+
.map_err(|e| {
40+
ErrorContext::msg(e)
41+
.unexpected(Value(value))
42+
.within(arg)
43+
.to_string()
44+
})?;
3845
}
3946
Long("shout") => {
4047
shout = true;
4148
}
4249
Value(val) if thing.is_none() => {
43-
thing = Some(
44-
val.to_str()
45-
.ok_or_else(|| ErrorContext::msg("invalid string").unexpected(arg))?,
46-
);
50+
thing = Some(val.to_str().ok_or_else(|| {
51+
ErrorContext::msg("invalid string")
52+
.unexpected(arg)
53+
.to_string()
54+
})?);
4755
}
4856
Short("h") | Long("help") => {
4957
println!("Usage: hello [-n|--number=NUM] [--shout] THING");
@@ -52,22 +60,25 @@ fn parse_args() -> Result<Args> {
5260
_ => {
5361
return Err(ErrorContext::msg("unexpected argument")
5462
.unexpected(arg)
55-
.within(Value(bin_name))
56-
.into());
63+
.to_string());
5764
}
5865
}
5966
}
6067

6168
Ok(Args {
6269
thing: thing
63-
.ok_or_else(|| ErrorContext::msg("missing argument THING").within(Value(bin_name)))?
70+
.ok_or_else(|| {
71+
ErrorContext::msg("missing argument THING")
72+
.within(Value(bin_name))
73+
.to_string()
74+
})?
6475
.to_owned(),
6576
number,
6677
shout,
6778
})
6879
}
6980

70-
fn main() -> Result<()> {
81+
fn main() -> Result<(), String> {
7182
let args = parse_args()?;
7283
let mut message = format!("Hello {}", args.thing);
7384
if args.shout {

crates/lexarg-error/src/lib.rs

Lines changed: 15 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -19,52 +19,12 @@
1919
#[cfg(doctest)]
2020
pub struct ReadmeDoctests;
2121

22-
/// `Result` that defaults to [`Error`]
23-
pub type Result<T, E = Error> = std::result::Result<T, E>;
24-
25-
/// Argument error type for use with lexarg
26-
pub struct Error {
27-
msg: String,
28-
}
29-
30-
impl Error {
31-
/// Create a new error object from a printable error message.
32-
#[cold]
33-
pub fn msg<M>(message: M) -> Self
34-
where
35-
M: std::fmt::Display,
36-
{
37-
Self {
38-
msg: message.to_string(),
39-
}
40-
}
41-
}
42-
43-
impl From<ErrorContext<'_>> for Error {
44-
#[cold]
45-
fn from(error: ErrorContext<'_>) -> Self {
46-
Self::msg(error.to_string())
47-
}
48-
}
49-
50-
impl std::fmt::Debug for Error {
51-
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52-
self.msg.fmt(formatter)
53-
}
54-
}
55-
56-
impl std::fmt::Display for Error {
57-
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58-
self.msg.fmt(formatter)
59-
}
60-
}
61-
62-
/// Collect context for creating an [`Error`]
22+
/// Collect context for creating an error
6323
#[derive(Debug)]
6424
pub struct ErrorContext<'a> {
6525
msg: String,
66-
within: Option<lexarg::Arg<'a>>,
67-
unexpected: Option<lexarg::Arg<'a>>,
26+
within: Option<lexarg_parser::Arg<'a>>,
27+
unexpected: Option<lexarg_parser::Arg<'a>>,
6828
}
6929

7030
impl<'a> ErrorContext<'a> {
@@ -81,16 +41,16 @@ impl<'a> ErrorContext<'a> {
8141
}
8242
}
8343

84-
/// [`Arg`][lexarg::Arg] the error occurred within
44+
/// [`Arg`][lexarg_parser::Arg] the error occurred within
8545
#[cold]
86-
pub fn within(mut self, within: lexarg::Arg<'a>) -> Self {
46+
pub fn within(mut self, within: lexarg_parser::Arg<'a>) -> Self {
8747
self.within = Some(within);
8848
self
8949
}
9050

91-
/// The failing [`Arg`][lexarg::Arg]
51+
/// The failing [`Arg`][lexarg_parser::Arg]
9252
#[cold]
93-
pub fn unexpected(mut self, unexpected: lexarg::Arg<'a>) -> Self {
53+
pub fn unexpected(mut self, unexpected: lexarg_parser::Arg<'a>) -> Self {
9454
self.unexpected = Some(unexpected);
9555
self
9656
}
@@ -112,10 +72,10 @@ impl std::fmt::Display for ErrorContext<'_> {
11272
if let Some(unexpected) = &self.unexpected {
11373
write!(formatter, ", found `")?;
11474
match unexpected {
115-
lexarg::Arg::Short(short) => write!(formatter, "-{short}")?,
116-
lexarg::Arg::Long(long) => write!(formatter, "--{long}")?,
117-
lexarg::Arg::Escape(value) => write!(formatter, "{value}")?,
118-
lexarg::Arg::Value(value) | lexarg::Arg::Unexpected(value) => {
75+
lexarg_parser::Arg::Short(short) => write!(formatter, "-{short}")?,
76+
lexarg_parser::Arg::Long(long) => write!(formatter, "--{long}")?,
77+
lexarg_parser::Arg::Escape(value) => write!(formatter, "{value}")?,
78+
lexarg_parser::Arg::Value(value) | lexarg_parser::Arg::Unexpected(value) => {
11979
write!(formatter, "{}", value.to_string_lossy())?;
12080
}
12181
}
@@ -124,10 +84,10 @@ impl std::fmt::Display for ErrorContext<'_> {
12484
if let Some(within) = &self.within {
12585
write!(formatter, " when parsing `")?;
12686
match within {
127-
lexarg::Arg::Short(short) => write!(formatter, "-{short}")?,
128-
lexarg::Arg::Long(long) => write!(formatter, "--{long}")?,
129-
lexarg::Arg::Escape(value) => write!(formatter, "{value}")?,
130-
lexarg::Arg::Value(value) | lexarg::Arg::Unexpected(value) => {
87+
lexarg_parser::Arg::Short(short) => write!(formatter, "-{short}")?,
88+
lexarg_parser::Arg::Long(long) => write!(formatter, "--{long}")?,
89+
lexarg_parser::Arg::Escape(value) => write!(formatter, "{value}")?,
90+
lexarg_parser::Arg::Value(value) | lexarg_parser::Arg::Unexpected(value) => {
13191
write!(formatter, "{}", value.to_string_lossy())?;
13292
}
13393
}

crates/lexarg-parser/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Change Log
2+
All notable changes to this project will be documented in this file.
3+
4+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
5+
and this project adheres to [Semantic Versioning](http://semver.org/).
6+
7+
<!-- next-header -->
8+
## [Unreleased] - ReleaseDate
9+
10+
<!-- next-url -->
11+
[Unreleased]: https://github.com/rust-cli/argfile/compare/716170eaa853ddf3032baa9b107eb3e44d6a4124...HEAD

crates/lexarg-parser/Cargo.toml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[package]
2+
name = "lexarg-parser"
3+
version = "0.1.0"
4+
description = "Minimal, API stable CLI parser"
5+
categories = ["command-line-interface"]
6+
keywords = ["args", "arguments", "cli", "parser", "getopt"]
7+
repository.workspace = true
8+
license.workspace = true
9+
edition.workspace = true
10+
rust-version.workspace = true
11+
include.workspace = true
12+
13+
[package.metadata.docs.rs]
14+
all-features = true
15+
rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]
16+
17+
[package.metadata.release]
18+
pre-release-replacements = [
19+
{file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1},
20+
{file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1},
21+
{file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1},
22+
{file="CHANGELOG.md", search="<!-- next-header -->", replace="<!-- next-header -->\n## [Unreleased] - ReleaseDate\n", exactly=1},
23+
{file="CHANGELOG.md", search="<!-- next-url -->", replace="<!-- next-url -->\n[Unreleased]: https://github.com/epage/pytest-rs/compare/{{tag_name}}...HEAD", exactly=1},
24+
]
25+
26+
[features]
27+
default = []
28+
29+
[dependencies]
30+
31+
[dev-dependencies]
32+
33+
[lints]
34+
workspace = true

0 commit comments

Comments
 (0)