From 2ea2a904e8d3cae4c022687a79589f9228d96a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Riegel?= <96702577+LoicRiegel@users.noreply.github.com> Date: Thu, 20 Mar 2025 17:35:50 +0100 Subject: [PATCH] Math commands can work with bounded ranges and produce list of numbers (#15319) No associated issue, but follows up #15135. See also discussion on [discord](https://discord.com/channels/601130461678272522/1349139634281513093/1349139639356624966) with @sholderbach # Description ### Math commands `range -> list` This enables the following math commands: - abs - ceil - floor - log - round to work with ranges. When a range is given, the command will apply the command on each item of the range, thus producing a list of number as output. Example ![image](https://github.com/user-attachments/assets/cff12724-5b26-4dbb-a979-a91c1b5652fc) The commands still do not work work with unbounded ranges: ![image](https://github.com/user-attachments/assets/40c766a8-763f-461d-971b-2d58d11fc3a6) And I left out the "mode" command because I think it does not make sense to use it on ranges... ### Math commands `range -> number` This was the topic of my previous PR, but for whatever reason I didn't do `math variance` and `math stddev`. I had to use `input.try_expand_range` to convert the range into a list before computing the variance/stddev. ![image](https://github.com/user-attachments/assets/803954e7-1c2a-4c86-8b16-e16518131138) And same, does not work in infinite ranges: ![image](https://github.com/user-attachments/assets/8bfaae2b-34cc-453d-8764-e42c815d28d3) ### Also done: - find link in documentation # User-Facing Changes - Command signatures changes - ability to use some commands with unbounded ranges - ability to use variance and stddev with bounded ranges # Tests + Formatting Cargo fmt and clippy OK Tests OK # After Submitting I guess nothing, or maybe release notes? --- crates/nu-command/src/math/abs.rs | 29 +++++++++++++++++ crates/nu-command/src/math/ceil.rs | 29 +++++++++++++++++ crates/nu-command/src/math/floor.rs | 29 +++++++++++++++++ crates/nu-command/src/math/log.rs | 31 +++++++++++++++++++ crates/nu-command/src/math/mode.rs | 6 ++-- crates/nu-command/src/math/round.rs | 29 +++++++++++++++++ crates/nu-command/src/math/sqrt.rs | 29 +++++++++++++++++ crates/nu-command/src/math/stddev.rs | 25 +++++++++++++++ crates/nu-command/src/math/variance.rs | 25 +++++++++++++++ crates/nu-command/tests/commands/math/abs.rs | 14 +++++++-- crates/nu-command/tests/commands/math/ceil.rs | 14 +++++++-- .../nu-command/tests/commands/math/floor.rs | 12 +++++-- crates/nu-command/tests/commands/math/log.rs | 14 +++++++-- .../nu-command/tests/commands/math/round.rs | 14 +++++++-- crates/nu-command/tests/commands/math/sqrt.rs | 12 +++++-- .../nu-command/tests/commands/math/stddev.rs | 12 +++++-- .../tests/commands/math/variance.rs | 12 +++++-- devdocs/README.md | 2 +- 18 files changed, 314 insertions(+), 24 deletions(-) diff --git a/crates/nu-command/src/math/abs.rs b/crates/nu-command/src/math/abs.rs index 4fae0633c8..5ebae80e2f 100644 --- a/crates/nu-command/src/math/abs.rs +++ b/crates/nu-command/src/math/abs.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathAbs; @@ -21,6 +23,7 @@ impl Command for MathAbs { Type::List(Box::new(Type::Duration)), Type::List(Box::new(Type::Duration)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -46,6 +49,19 @@ impl Command for MathAbs { input: PipelineData, ) -> Result { let head = call.head; + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map(move |value| abs_helper(value, head), engine_state.signals()) } @@ -56,6 +72,19 @@ impl Command for MathAbs { input: PipelineData, ) -> Result { let head = call.head; + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| abs_helper(value, head), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/ceil.rs b/crates/nu-command/src/math/ceil.rs index 5867f21bca..585b12aa62 100644 --- a/crates/nu-command/src/math/ceil.rs +++ b/crates/nu-command/src/math/ceil.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathCeil; @@ -16,6 +18,7 @@ impl Command for MathCeil { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Int)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -45,6 +48,19 @@ impl Command for MathCeil { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map(move |value| operate(value, head), engine_state.signals()) } @@ -59,6 +75,19 @@ impl Command for MathCeil { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/floor.rs b/crates/nu-command/src/math/floor.rs index 2bc705f926..73760a390a 100644 --- a/crates/nu-command/src/math/floor.rs +++ b/crates/nu-command/src/math/floor.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathFloor; @@ -16,6 +18,7 @@ impl Command for MathFloor { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Int)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -45,6 +48,19 @@ impl Command for MathFloor { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map(move |value| operate(value, head), engine_state.signals()) } @@ -59,6 +75,19 @@ impl Command for MathFloor { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/log.rs b/crates/nu-command/src/math/log.rs index 79eed71640..eff8c583df 100644 --- a/crates/nu-command/src/math/log.rs +++ b/crates/nu-command/src/math/log.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; use nu_protocol::Signals; #[derive(Clone)] @@ -22,6 +24,7 @@ impl Command for MathLog { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Float)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -46,7 +49,21 @@ impl Command for MathLog { call: &Call, input: PipelineData, ) -> Result { + let head = call.head; let base: Spanned = call.req(engine_state, stack, 0)?; + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } log(base, call.head, input, engine_state.signals()) } @@ -56,7 +73,21 @@ impl Command for MathLog { call: &Call, input: PipelineData, ) -> Result { + let head = call.head; let base: Spanned = call.req_const(working_set, 0)?; + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } log(base, call.head, input, working_set.permanent().signals()) } diff --git a/crates/nu-command/src/math/mode.rs b/crates/nu-command/src/math/mode.rs index 5183a855a9..e9e827ad83 100644 --- a/crates/nu-command/src/math/mode.rs +++ b/crates/nu-command/src/math/mode.rs @@ -110,7 +110,7 @@ impl Command for MathMode { } } -pub fn mode(values: &[Value], _span: Span, head: Span) -> Result { +pub fn mode(values: &[Value], span: Span, head: Span) -> Result { //In e-q, Value doesn't implement Hash or Eq, so we have to get the values inside // But f64 doesn't implement Hash, so we get the binary representation to use as // key in the HashMap @@ -130,11 +130,11 @@ pub fn mode(values: &[Value], _span: Span, head: Span) -> Result Err(*error.clone()), - other => Err(ShellError::UnsupportedInput { + _ => Err(ShellError::UnsupportedInput { msg: "Unable to give a result with this input".to_string(), input: "value originates from here".into(), msg_span: head, - input_span: other.span(), + input_span: span, }), }) .collect::, ShellError>>()?; diff --git a/crates/nu-command/src/math/round.rs b/crates/nu-command/src/math/round.rs index 558715e675..aa04839e32 100644 --- a/crates/nu-command/src/math/round.rs +++ b/crates/nu-command/src/math/round.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathRound; @@ -16,6 +18,7 @@ impl Command for MathRound { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Number)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .named( @@ -52,6 +55,19 @@ impl Command for MathRound { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head, precision_param), engine_state.signals(), @@ -70,6 +86,19 @@ impl Command for MathRound { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head, precision_param), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/sqrt.rs b/crates/nu-command/src/math/sqrt.rs index 38b2a4d800..7bb5ccc78e 100644 --- a/crates/nu-command/src/math/sqrt.rs +++ b/crates/nu-command/src/math/sqrt.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathSqrt; @@ -16,6 +18,7 @@ impl Command for MathSqrt { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Float)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -45,6 +48,19 @@ impl Command for MathSqrt { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map(move |value| operate(value, head), engine_state.signals()) } @@ -59,6 +75,19 @@ impl Command for MathSqrt { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/stddev.rs b/crates/nu-command/src/math/stddev.rs index 051f7d02d7..2987949e05 100644 --- a/crates/nu-command/src/math/stddev.rs +++ b/crates/nu-command/src/math/stddev.rs @@ -14,6 +14,7 @@ impl Command for MathStddev { Signature::build("math stddev") .input_output_types(vec![ (Type::List(Box::new(Type::Number)), Type::Number), + (Type::Range, Type::Number), (Type::table(), Type::record()), (Type::record(), Type::record()), ]) @@ -53,6 +54,18 @@ impl Command for MathStddev { input: PipelineData, ) -> Result { let sample = call.has_flag(engine_state, stack, "sample")?; + let name = call.head; + let span = input.span().unwrap_or(name); + let input: PipelineData = match input.try_expand_range() { + Err(_) => { + return Err(ShellError::IncorrectValue { + msg: "Range must be bounded".to_string(), + val_span: span, + call_span: name, + }); + } + Ok(val) => val, + }; run_with_function(call, input, compute_stddev(sample)) } @@ -63,6 +76,18 @@ impl Command for MathStddev { input: PipelineData, ) -> Result { let sample = call.has_flag_const(working_set, "sample")?; + let name = call.head; + let span = input.span().unwrap_or(name); + let input: PipelineData = match input.try_expand_range() { + Err(_) => { + return Err(ShellError::IncorrectValue { + msg: "Range must be bounded".to_string(), + val_span: span, + call_span: name, + }); + } + Ok(val) => val, + }; run_with_function(call, input, compute_stddev(sample)) } diff --git a/crates/nu-command/src/math/variance.rs b/crates/nu-command/src/math/variance.rs index b221d92746..92712872f5 100644 --- a/crates/nu-command/src/math/variance.rs +++ b/crates/nu-command/src/math/variance.rs @@ -13,6 +13,7 @@ impl Command for MathVariance { Signature::build("math variance") .input_output_types(vec![ (Type::List(Box::new(Type::Number)), Type::Number), + (Type::Range, Type::Number), (Type::table(), Type::record()), (Type::record(), Type::record()), ]) @@ -45,6 +46,18 @@ impl Command for MathVariance { input: PipelineData, ) -> Result { let sample = call.has_flag(engine_state, stack, "sample")?; + let name = call.head; + let span = input.span().unwrap_or(name); + let input: PipelineData = match input.try_expand_range() { + Err(_) => { + return Err(ShellError::IncorrectValue { + msg: "Range must be bounded".to_string(), + val_span: span, + call_span: name, + }); + } + Ok(val) => val, + }; run_with_function(call, input, compute_variance(sample)) } @@ -55,6 +68,18 @@ impl Command for MathVariance { input: PipelineData, ) -> Result { let sample = call.has_flag_const(working_set, "sample")?; + let name = call.head; + let span = input.span().unwrap_or(name); + let input: PipelineData = match input.try_expand_range() { + Err(_) => { + return Err(ShellError::IncorrectValue { + msg: "Range must be bounded".to_string(), + val_span: span, + call_span: name, + }); + } + Ok(val) => val, + }; run_with_function(call, input, compute_variance(sample)) } diff --git a/crates/nu-command/tests/commands/math/abs.rs b/crates/nu-command/tests/commands/math/abs.rs index de5c7551aa..4ddafd5bb0 100644 --- a/crates/nu-command/tests/commands/math/abs.rs +++ b/crates/nu-command/tests/commands/math/abs.rs @@ -7,8 +7,16 @@ fn const_abs() { } #[test] -fn cannot_abs_range() { - let actual = nu!("0..5 | math abs"); +fn can_abs_range_into_list() { + let actual = nu!("-1.5..-10.5 | math abs"); + let expected = nu!("1.5..10.5"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_abs_infinite_range() { + let actual = nu!("0.. | math abs"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/ceil.rs b/crates/nu-command/tests/commands/math/ceil.rs index f9c753d1dd..e7377efec4 100644 --- a/crates/nu-command/tests/commands/math/ceil.rs +++ b/crates/nu-command/tests/commands/math/ceil.rs @@ -7,8 +7,16 @@ fn const_ceil() { } #[test] -fn cannot_ceil_range() { - let actual = nu!("0..5 | math ceil"); +fn can_ceil_range_into_list() { + let actual = nu!("(1.8)..(3.8) | math ceil"); + let expected = nu!("[2 3 4]"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_ceil_infinite_range() { + let actual = nu!("0.. | math ceil"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/floor.rs b/crates/nu-command/tests/commands/math/floor.rs index 5517233caa..0cf2a47946 100644 --- a/crates/nu-command/tests/commands/math/floor.rs +++ b/crates/nu-command/tests/commands/math/floor.rs @@ -7,8 +7,16 @@ fn const_floor() { } #[test] -fn cannot_floor_range() { +fn can_floor_range_into_list() { + let actual = nu!("(1.8)..(3.8) | math floor"); + let expected = nu!("[1 2 3]"); + + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_floor_infinite_range() { let actual = nu!("0.. | math floor"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/log.rs b/crates/nu-command/tests/commands/math/log.rs index db69378e41..23d6abd7cb 100644 --- a/crates/nu-command/tests/commands/math/log.rs +++ b/crates/nu-command/tests/commands/math/log.rs @@ -7,8 +7,16 @@ fn const_log() { } #[test] -fn cannot_log_range() { - let actual = nu!("0.. | math log 2"); +fn can_log_range_into_list() { + let actual = nu!("1..5 | math log 2"); + let expected = nu!("[1 2 3 4 5] | math log 2"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_log_infinite_range() { + let actual = nu!("1.. | math log 2"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/round.rs b/crates/nu-command/tests/commands/math/round.rs index 2c3badad5e..70b7567354 100644 --- a/crates/nu-command/tests/commands/math/round.rs +++ b/crates/nu-command/tests/commands/math/round.rs @@ -42,8 +42,16 @@ fn const_round() { } #[test] -fn cannot_round_infinite_range() { - let actual = nu!("0..5 | math round"); +fn can_round_range_into_list() { + let actual = nu!("(1.0)..(1.2)..(2.0) | math round"); + let expected = nu!("[1 1 1 2 2 2]"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_round_infinite_range() { + let actual = nu!("0.. | math round"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/sqrt.rs b/crates/nu-command/tests/commands/math/sqrt.rs index 9f5cc55f88..3da12fab7c 100644 --- a/crates/nu-command/tests/commands/math/sqrt.rs +++ b/crates/nu-command/tests/commands/math/sqrt.rs @@ -28,8 +28,16 @@ fn const_sqrt() { } #[test] -fn cannot_sqrt_range() { +fn can_sqrt_range() { let actual = nu!("0..5 | math sqrt"); + let expected = nu!("[0 1 2 3 4 5] | math sqrt"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_sqrt_infinite_range() { + let actual = nu!("0.. | math sqrt"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/stddev.rs b/crates/nu-command/tests/commands/math/stddev.rs index f1688c2d7a..c8398d5637 100644 --- a/crates/nu-command/tests/commands/math/stddev.rs +++ b/crates/nu-command/tests/commands/math/stddev.rs @@ -7,8 +7,16 @@ fn const_avg() { } #[test] -fn cannot_stddev_range() { +fn can_stddev_range() { let actual = nu!("0..5 | math stddev"); + let expected = nu!("[0 1 2 3 4 5] | math stddev"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_stddev_infinite_range() { + let actual = nu!("0.. | math stddev"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/variance.rs b/crates/nu-command/tests/commands/math/variance.rs index 1573a131bb..b31d75e148 100644 --- a/crates/nu-command/tests/commands/math/variance.rs +++ b/crates/nu-command/tests/commands/math/variance.rs @@ -7,8 +7,16 @@ fn const_variance() { } #[test] -fn cannot_variance_range() { +fn can_variance_range() { let actual = nu!("0..5 | math variance"); + let expected = nu!("[0 1 2 3 4 5] | math variance"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_variance_infinite_range() { + let actual = nu!("0.. | math variance"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/devdocs/README.md b/devdocs/README.md index fe558d5e65..08a6a29dc5 100644 --- a/devdocs/README.md +++ b/devdocs/README.md @@ -9,4 +9,4 @@ A complementary (currently stale) resource has been the [Nushell contributor boo - [Developer FAQ](FAQ.md) - [How to/SOPs](HOWTOS.md) - [Platform support policy](PLATFORM_SUPPORT.md) -- [Our Rust style](devdocs/rust_style.md) +- [Our Rust style](rust_style.md)