diff --git a/crates/nu-plugin/src/protocol/evaluated_call.rs b/crates/nu-plugin/src/protocol/evaluated_call.rs index 52b4c3031f..be15d4e224 100644 --- a/crates/nu-plugin/src/protocol/evaluated_call.rs +++ b/crates/nu-plugin/src/protocol/evaluated_call.rs @@ -53,10 +53,10 @@ impl EvaluatedCall { }) } - /// Indicates whether named parameter is present in the arguments - /// - /// Typically this method would be used on a flag parameter, a named parameter - /// that does not take a value. + /// Check if a flag (named parameter that does not take a value) is set + /// Returns Ok(true) if flag is set or passed true value + /// Returns Ok(false) if flag is not set or passed false value + /// Returns Err if passed value is not a boolean /// /// # Examples /// Invoked as `my_command --foo`: @@ -72,7 +72,7 @@ impl EvaluatedCall { /// # None /// # )], /// # }; - /// assert!(call.has_flag("foo")); + /// assert!(call.has_flag("foo").unwrap()); /// ``` /// /// Invoked as `my_command --bar`: @@ -88,16 +88,73 @@ impl EvaluatedCall { /// # None /// # )], /// # }; - /// assert!(!call.has_flag("foo")); + /// assert!(!call.has_flag("foo").unwrap()); /// ``` - pub fn has_flag(&self, flag_name: &str) -> bool { + /// + /// Invoked as `my_command --foo=true`: + /// ``` + /// # use nu_protocol::{Spanned, Span, Value}; + /// # use nu_plugin::EvaluatedCall; + /// # let null_span = Span::new(0, 0); + /// # let call = EvaluatedCall { + /// # head: null_span, + /// # positional: Vec::new(), + /// # named: vec![( + /// # Spanned { item: "foo".to_owned(), span: null_span}, + /// # Some(Value::bool(true, Span::unknown())) + /// # )], + /// # }; + /// assert!(call.has_flag("foo").unwrap()); + /// ``` + /// + /// Invoked as `my_command --foo=false`: + /// ``` + /// # use nu_protocol::{Spanned, Span, Value}; + /// # use nu_plugin::EvaluatedCall; + /// # let null_span = Span::new(0, 0); + /// # let call = EvaluatedCall { + /// # head: null_span, + /// # positional: Vec::new(), + /// # named: vec![( + /// # Spanned { item: "foo".to_owned(), span: null_span}, + /// # Some(Value::bool(false, Span::unknown())) + /// # )], + /// # }; + /// assert!(!call.has_flag("foo").unwrap()); + /// ``` + /// + /// Invoked with wrong type as `my_command --foo=1`: + /// ``` + /// # use nu_protocol::{Spanned, Span, Value}; + /// # use nu_plugin::EvaluatedCall; + /// # let null_span = Span::new(0, 0); + /// # let call = EvaluatedCall { + /// # head: null_span, + /// # positional: Vec::new(), + /// # named: vec![( + /// # Spanned { item: "foo".to_owned(), span: null_span}, + /// # Some(Value::int(1, Span::unknown())) + /// # )], + /// # }; + /// assert!(call.has_flag("foo").is_err()); + /// ``` + pub fn has_flag(&self, flag_name: &str) -> Result { for name in &self.named { if flag_name == name.0.item { - return true; + return match &name.1 { + Some(Value::Bool { val, .. }) => Ok(*val), + None => Ok(true), + Some(result) => Err(ShellError::CantConvert { + to_type: "bool".into(), + from_type: result.get_type().to_string(), + span: result.span(), + help: Some("".into()), + }), + }; } } - false + Ok(false) } /// Returns the [`Value`] of an optional named argument @@ -340,7 +397,7 @@ mod test { let name: Option = call.get_flag("name").unwrap(); assert_eq!(name, Some(1.0)); - assert!(call.has_flag("flag")); + assert!(call.has_flag("flag").unwrap()); let required: f64 = call.req(0).unwrap(); assert!((required - 1.0).abs() < f64::EPSILON); diff --git a/crates/nu_plugin_example/src/example.rs b/crates/nu_plugin_example/src/example.rs index 226972be98..45607c8b4b 100644 --- a/crates/nu_plugin_example/src/example.rs +++ b/crates/nu_plugin_example/src/example.rs @@ -40,7 +40,7 @@ impl Example { // Keep this in mind when designing your plugin signatures let a: i64 = call.req(0)?; let b: String = call.req(1)?; - let flag = call.has_flag("flag"); + let flag = call.has_flag("flag")?; let opt: Option = call.opt(2)?; let named: Option = call.get_flag("named")?; let rest: Vec = call.rest(3)?; diff --git a/crates/nu_plugin_inc/src/nu/mod.rs b/crates/nu_plugin_inc/src/nu/mod.rs index b924e8e135..5d2b6fa0a1 100644 --- a/crates/nu_plugin_inc/src/nu/mod.rs +++ b/crates/nu_plugin_inc/src/nu/mod.rs @@ -40,13 +40,13 @@ impl Plugin for Inc { self.cell_path = cell_path; - if call.has_flag("major") { + if call.has_flag("major")? { self.for_semver(SemVerAction::Major); } - if call.has_flag("minor") { + if call.has_flag("minor")? { self.for_semver(SemVerAction::Minor); } - if call.has_flag("patch") { + if call.has_flag("patch")? { self.for_semver(SemVerAction::Patch); } diff --git a/crates/nu_plugin_query/src/query_web.rs b/crates/nu_plugin_query/src/query_web.rs index 5fca72038e..d87ef38466 100644 --- a/crates/nu_plugin_query/src/query_web.rs +++ b/crates/nu_plugin_query/src/query_web.rs @@ -35,13 +35,13 @@ pub fn parse_selector_params(call: &EvaluatedCall, input: &Value) -> Result q2, None => "".to_string(), }; - let as_html = call.has_flag("as-html"); + let as_html = call.has_flag("as-html")?; let attribute = call.get_flag("attribute")?.unwrap_or_default(); let as_table: Value = call .get_flag("as-table")? .unwrap_or_else(|| Value::nothing(head)); - let inspect = call.has_flag("inspect"); + let inspect = call.has_flag("inspect")?; if !&query.is_empty() && ScraperSelector::parse(&query).is_err() { return Err(LabeledError { diff --git a/tests/plugins/core_inc.rs b/tests/plugins/core_inc.rs index b50ad2cc08..28017c4b23 100644 --- a/tests/plugins/core_inc.rs +++ b/tests/plugins/core_inc.rs @@ -148,3 +148,16 @@ fn semversion_without_passing_field() { assert_eq!(actual.out, "0.1.4"); }) } + +#[test] +fn explicit_flag() { + Playground::setup("plugin_inc_test_6", |dirs, _| { + let actual = nu_with_plugins!( + cwd: dirs.test(), + plugin: ("nu_plugin_inc"), + "'0.1.2' | inc --major=false --minor=true --patch=false" + ); + + assert_eq!(actual.out, "0.2.0"); + }) +}