diff --git a/CHANGELOG.md b/CHANGELOG.md index cc6f9a9..f721aa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,16 @@ # CHANGELOG -## Future +## v0.6.0 - Add `all_arg`, `remaining` and `cur_remaining` to `Pareg`. - Add `cur_val_or_next` to `Pareg`. - Add new error for checking value validity `ArgError::InvalidValue`. - Add `err_invalid`, `err_invalid_value` and `err_invalid_span` to `Pareg`. - Make `ArgErrCtx::from_msg` take `impl Into` instead of `String`. - Add `ArgErrCtx::spanned` and `ArgError::spanned`. +- Add `ArgErrCtx::from_inner`. +- Add `part_of`, `inline_msg` and `main_msg` to `ArgErrCtx` and `ArgError`. +- Add `parse_msg` and `err` to `ArgError` +- Require `FromArg` to return `Result` - Remove unncesary mut requirements on `Pareg`. ## v0.5.2 diff --git a/Cargo.lock b/Cargo.lock index 098e269..017948d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "bitflags" @@ -34,7 +34,7 @@ dependencies = [ [[package]] name = "pareg" -version = "0.5.2" +version = "0.6.0" dependencies = [ "pareg_core", "pareg_proc", @@ -42,7 +42,7 @@ dependencies = [ [[package]] name = "pareg_core" -version = "0.5.2" +version = "0.6.0" dependencies = [ "proc-macro2", "quote", @@ -53,7 +53,7 @@ dependencies = [ [[package]] name = "pareg_proc" -version = "0.5.2" +version = "0.6.0" dependencies = [ "pareg_core", ] diff --git a/Cargo.toml b/Cargo.toml index 37991b2..8e4f9ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pareg" -version = "0.5.2" +version = "0.6.0" edition = "2021" license-file = "LICENSE" description = "Rust library with useful tools for command line argument parsing" @@ -17,5 +17,5 @@ members = [ ] [dependencies] -pareg_core = { version = "0.5.2", path = "pareg_core" } -pareg_proc = { version = "0.5.2", path = "pareg_proc" } +pareg_core = { version = "0.6.0", path = "pareg_core" } +pareg_proc = { version = "0.6.0", path = "pareg_proc" } diff --git a/pareg_core/Cargo.toml b/pareg_core/Cargo.toml index 384bdaa..9cfee74 100644 --- a/pareg_core/Cargo.toml +++ b/pareg_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pareg_core" -version = "0.5.2" +version = "0.6.0" edition = "2021" license-file = "../LICENSE" description = "This library contains the implementation for the pareg library." diff --git a/pareg_core/src/err/arg_err_ctx.rs b/pareg_core/src/err/arg_err_ctx.rs index 4710088..63aa5c5 100644 --- a/pareg_core/src/err/arg_err_ctx.rs +++ b/pareg_core/src/err/arg_err_ctx.rs @@ -25,18 +25,21 @@ pub struct ArgErrCtx { } impl ArgErrCtx { + pub fn from_inner(e: E, arg: String) -> Self { + Self::from_msg(e.to_string(), arg) + } + /// Creates simple error with just message and the errornous argument. pub fn from_msg( message: impl Into>, arg: String, ) -> Self { - let message = message.into(); Self { error_span: 0..arg.len(), args: vec![arg], error_idx: 0, - long_message: Some(message.clone()), - message, + long_message: None, + message: message.into(), hint: None, color: ColorMode::default(), } @@ -51,6 +54,22 @@ impl ArgErrCtx { self } + /// Sets new argument. If the original argument is substring of this, + /// span will be adjusted. + pub fn part_of(mut self, arg: String) -> Self { + if self.args[self.error_idx].len() == arg.len() { + self.error_span = 0..arg.len(); + self.args[self.error_idx] = arg; + return self; + } + if let Some(shift) = arg.find(&self.args[self.error_idx]) { + self.error_span.start += shift; + self.error_span.end += shift; + } + self.args[self.error_idx] = arg; + self + } + /// Add arguments to the error so that it may have better error message. /// Mostly useful internaly in pareg. pub fn add_args(mut self, args: Vec, idx: usize) -> Self { @@ -76,6 +95,18 @@ impl ArgErrCtx { self.error_span = span; self } + + /// Sets the short message that is inlined with the code. + pub fn inline_msg(mut self, msg: impl Into>) -> Self { + self.message = msg.into(); + self + } + + /// Sets the primary (non inline) message. + pub fn main_msg(mut self, msg: impl Into>) -> Self { + self.long_message = Some(msg.into()); + self + } } impl Display for ArgErrCtx { diff --git a/pareg_core/src/err/arg_error.rs b/pareg_core/src/err/arg_error.rs index f3d6b79..818da5a 100644 --- a/pareg_core/src/err/arg_error.rs +++ b/pareg_core/src/err/arg_error.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, ops::Range}; use thiserror::Error; -use super::ArgErrCtx; +use super::{ArgErrCtx, Result}; /// Errors thrown when parsing arguments. #[derive(Debug, Error)] @@ -36,6 +36,11 @@ pub enum ArgError { } impl ArgError { + /// Shortcut for creating parse error. + pub fn parse_msg(msg: impl Into>, arg: String) -> Self { + Self::FailedToParse(Box::new(ArgErrCtx::from_msg(msg, arg))) + } + /// Moves the span in the error message by `cnt` and changes the /// errornous argument to `new_arg`. pub fn shift_span(self, cnt: usize, new_arg: String) -> Self { @@ -58,6 +63,27 @@ impl ArgError { self.map_ctx(|c| c.spanned(span)) } + /// Sets the short message that is inlined with the code. + pub fn inline_msg(self, msg: impl Into>) -> Self { + self.map_ctx(|c| c.inline_msg(msg)) + } + + /// Sets the primary (non inline) message. + pub fn main_msg(self, msg: impl Into>) -> Self { + self.map_ctx(|c| c.main_msg(msg)) + } + + /// Sets new argument. If the original argument is substring of this, + /// span will be adjusted. + pub fn part_of(self, arg: String) -> Self { + self.map_ctx(|c| c.part_of(arg)) + } + + /// Helper method to wrap this in error and make it a result. + pub fn err(self) -> Result { + Err(self) + } + pub fn map_ctx(self, f: impl FnOnce(ArgErrCtx) -> ArgErrCtx) -> Self { match self { ArgError::UnknownArgument(mut ctx) => { diff --git a/pareg_core/src/from_arg.rs b/pareg_core/src/from_arg.rs index 3b295ca..854aca8 100644 --- a/pareg_core/src/from_arg.rs +++ b/pareg_core/src/from_arg.rs @@ -1,7 +1,6 @@ use std::{ borrow::Cow, ffi::{OsStr, OsString}, - fmt::Display, net::{ IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, }, @@ -14,7 +13,7 @@ use std::{ use crate::{ err::{ArgError, Result}, impl_all::impl_all, - ArgErrCtx, ColorMode, + ArgErrCtx, }; /// Represents a trait similar to [`FromStr`], in addition it may return type @@ -35,40 +34,32 @@ pub trait FromArg<'a>: Sized { } /// Default implementation for [`FromArg`] for types that implement [`FromStr`] -pub trait FromArgStr: FromStr {} +pub trait FromArgStr: FromStr {} -impl<'a, T> FromArg<'a> for T +impl FromArg<'_> for T where T: FromArgStr, - T::Err: Display, { #[inline] fn from_arg(arg: &str) -> Result { - T::from_str(arg).map_err(|e| { - ArgError::FailedToParse( - ArgErrCtx { - args: vec![arg.into()], - error_idx: 0, - error_span: 0..arg.len(), - message: e.to_string().into(), - long_message: Some( - format!("Failed to parse the value `{arg}`: {e}.") - .into(), - ), - hint: None, - color: ColorMode::default(), - } - .into(), - ) - }) + T::from_str(arg) } } -impl_all! { FromArgStr: +impl_all! { impl<'a> FromArg<'a>: u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f32, f64, usize, isize, bool, char, String, PathBuf, OsString, IpAddr, SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, - => {} + => { + #[inline(always)] + fn from_arg(arg: &'a str) -> Result { + Self::from_str(arg).map_err(|e| { + ArgError::FailedToParse(Box::new( + ArgErrCtx::from_inner(e, arg.to_string()) + )) + }) + } + } } impl<'a> FromArg<'a> for &'a str { diff --git a/pareg_proc/Cargo.toml b/pareg_proc/Cargo.toml index 224cef0..a532209 100644 --- a/pareg_proc/Cargo.toml +++ b/pareg_proc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pareg_proc" -version = "0.5.2" +version = "0.6.0" edition = "2021" license-file = "../LICENSE" description = "This library contains proc macros for the pareg library." @@ -14,4 +14,4 @@ readme = "../README.md" proc-macro = true [dependencies] -pareg_core = { version = "0.5.2", path = "../pareg_core" } +pareg_core = { version = "0.6.0", path = "../pareg_core" }