Repository: pacak/bpaf
Pull request #381 (2024-07-29 22:08:47)

Test and a small refactor for non-strict positional
- copy is good when cheap
- exhaustive pattern match is good
- and we should be careful about suggesting completions - `--` doesn't fit there


Patch:
diff --git a/src/params.rs b/src/params.rs
index c33a3b0..ae9fc8d 100644
--- a/src/params.rs
+++ b/src/params.rs
@@ -726,7 +726,7 @@ pub struct ParsePositional<T> {
     ty: PhantomData<T>,
 }
 
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
 enum Position {
     Unrestricted,
     Strict,
@@ -811,22 +811,24 @@ fn parse_pos_word(
     args: &mut State,
     metavar: Metavar,
     help: &Option<Doc>,
-    position: &Position,
+    position: Position,
 ) -> Result<OsString, Error> {
     match args.take_positional_word(metavar) {
         Ok((ix, is_strict, word)) => {
             match position {
-                &Position::Strict if !is_strict => {
-                    #[cfg(feature = "autocomplete")]
-                    args.push_pos_sep();
-                    return Err(Error(Message::StrictPos(ix, metavar)));
+                Position::Strict => {
+                    if !is_strict {
+                        #[cfg(feature = "autocomplete")]
+                        args.push_pos_sep();
+                        return Err(Error(Message::StrictPos(ix, metavar)));
+                    }
                 }
-                &Position::NonStrict if is_strict => {
-                    #[cfg(feature = "autocomplete")]
-                    args.push_pos_sep();
-                    return Err(Error(Message::NonStrictPos(ix, metavar)));
+                Position::NonStrict => {
+                    if is_strict {
+                        return Err(Error(Message::NonStrictPos(ix, metavar)));
+                    }
                 }
-                _ => {}
+                Position::Unrestricted => {}
             }
 
             #[cfg(feature = "autocomplete")]
@@ -853,7 +855,7 @@ where
     <T as std::str::FromStr>::Err: std::fmt::Display,
 {
     fn eval(&self, args: &mut State) -> Result<T, Error> {
-        let os = parse_pos_word(args, Metavar(self.metavar), &self.help, &self.position)?;
+        let os = parse_pos_word(args, Metavar(self.metavar), &self.help, self.position)?;
         match parse_os_str::<T>(os) {
             Ok(ok) => Ok(ok),
             Err(err) => Err(Error(Message::ParseFailed(args.current, err))),


Test patch:
diff --git a/tests/completion.rs b/tests/completion.rs
index 9c5d2a4..6a7ab1d 100644
--- a/tests/completion.rs
+++ b/tests/completion.rs
@@ -936,6 +936,31 @@ fn should_be_able_to_suggest_double_dash() {
     assert_eq!(r, "--");
 }
 
+#[test]
+fn non_strict_and_double_dash() {
+    let a = short('a').switch();
+    let b = positional::<String>("B").non_strict();
+    let parser = construct!(a, b).to_options();
+
+    let r = parser
+        .run_inner(Args::from(&[""]).set_comp(0))
+        .unwrap_err()
+        .unwrap_stdout();
+
+    assert_eq!(
+        r,
+        "\
+-a\t-a\t\t
+\tB\t\t\n\n"
+    );
+
+    let r = parser
+        .run_inner(Args::from(&["--", ""]).set_comp(0))
+        .unwrap_err()
+        .unwrap_stdout();
+    assert_eq!(r, "\n");
+}
+
 #[test]
 fn suggest_double_dash_automatically_for_strictly_positional() {
     let a = short('a').switch();