Repository: pacak/bpaf
Pull request #78 (2022-09-26 00:47:30)

Cosmetics
Mostly cosmetic stuff + a simple test


Patch:
diff --git a/Changelog.md b/Changelog.md
index bd2f111..9f08a68 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,4 +1,9 @@
 # Change Log
+
+## bpaf [0.6.1] - unreleased
+- cosmetic improvements
+- completion info in sensors example
+
 ## bpaf [0.6.0] - 2022-09-22
 # What's new in 0.6.0
 - `adjacent` restriction to parse things in a tighter context
diff --git a/examples/sensors.rs b/examples/sensors.rs
index e8858df..ce81607 100644
--- a/examples/sensors.rs
+++ b/examples/sensors.rs
@@ -31,9 +31,32 @@ struct Opts {
     sensors: Vec<Sensor>,
 }
 
+// generates completion suggestions
+fn sensor_device_comp(input: &String) -> Vec<(String, Option<String>)> {
+    [
+        ("temp100", "Main temperature sensor"),
+        ("temp101", "Output temperature sensor"),
+        ("tank01", "Temperature in a storage tank 1"),
+        ("tank02", "Temperature in a storage tank 2"),
+        ("tank03", "Temperature in a storage tank 3"),
+        ("outdoor", "Outdoor temperature sensor"),
+    ]
+    .iter()
+    .filter_map(|(name, descr)| {
+        if name.starts_with(input) {
+            Some((name.to_string(), Some(descr.to_string())))
+        } else {
+            None
+        }
+    })
+    .collect::<Vec<_>>()
+}
+
 fn opts() -> Opts {
     let sensor = long("sensor").req_flag(());
-    let device = long("sensor-device").argument::<String>("DEVICE");
+    let device = long("sensor-device")
+        .argument::<String>("DEVICE")
+        .complete(sensor_device_comp);
     let name = long("sensor-name").argument::<String>("NAME");
 
     // from_str needs to be replaced with `parse` that can deal with hex digits
diff --git a/src/meta_usage.rs b/src/meta_usage.rs
index 59def31..a9607b9 100644
--- a/src/meta_usage.rs
+++ b/src/meta_usage.rs
@@ -62,7 +62,12 @@ fn collect_usage_meta(meta: &Meta, is_pos: &mut bool) -> Option<UsageMeta> {
                         usage_meta
                     );
                     *is_pos |= this_pos;
+
+                    if let UsageMeta::Or(_) = &usage_meta {
+                        Some(UsageMeta::Required(Box::new(usage_meta)))
+                    } else {
                     Some(usage_meta)
+                    }
                 })
                 .collect::<Vec<_>>();
             match items.len() {


Test patch:
diff --git a/tests/meta_usage.rs b/tests/meta_usage.rs
index 480bfe8..ae9c8fc 100644
--- a/tests/meta_usage.rs
+++ b/tests/meta_usage.rs
@@ -187,3 +187,39 @@ fn no_actual_arguments_also_works() {
     let x = pure(true).meta();
     assert_eq!("no parameters expected", x.to_string());
 }
+
+#[test]
+fn a_or_b() {
+    let a = short('a').long("aaa").argument::<String>("A");
+    let b = short('b').long("bbb").argument::<String>("B");
+    let parser = construct!([a, b]).to_options();
+    assert_usage(parser, "(-a A | -b B)");
+}
+
+#[test]
+fn a_or_b_and_c() {
+    let a = short('a').long("aaa").argument::<String>("A");
+    let b = short('b').long("bbb").argument::<String>("B");
+    let ab = construct!([a, b]);
+    let c = positional::<String>("C");
+    let parser = construct!(ab, c).to_options();
+    assert_usage(parser, "(-a A | -b B) <C>");
+}
+
+#[test]
+fn a_or_b_opt() {
+    let a = short('a').long("aaa").argument::<String>("A");
+    let b = short('b').long("bbb").argument::<String>("B");
+    let parser = construct!([a, b]).optional().to_options();
+    assert_usage(parser, "[-a A | -b B]");
+}
+
+#[test]
+fn a_or_b_opt_and_c() {
+    let a = short('a').long("aaa").argument::<String>("A");
+    let b = short('b').long("bbb").argument::<String>("B");
+    let ab = construct!([a, b]).optional();
+    let c = positional::<String>("C");
+    let parser = construct!(ab, c).to_options();
+    assert_usage(parser, "[-a A | -b B] <C>");
+}
diff --git a/tests/tests.rs b/tests/tests.rs
index 1df19f0..883603a 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -1611,3 +1611,20 @@ fn sneaky_command() {
     let r = parser.run_inner(Args::from(&["hello"])).unwrap();
     assert_eq!(r, Cmd::A(false));
 }
+
+#[test]
+fn default_for_many() {
+    let parser = positional::<String>("ROOTS")
+        .many()
+        .map(|items| {
+            if items.is_empty() {
+                vec![String::from(".")]
+            } else {
+                items
+            }
+        })
+        .to_options();
+
+    let r = parser.run_inner(Args::from(&[])).unwrap();
+    assert_eq!(r, vec![String::from(".")]);
+}