forked from extern/nushell
Merge branch 'main' of https://github.com/nushell/engine-q into plugins
This commit is contained in:
@ -15,7 +15,7 @@ impl Command for Use {
|
||||
}
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("use").required("pattern", SyntaxShape::String, "import pattern")
|
||||
Signature::build("use").rest("pattern", SyntaxShape::String, "import pattern parts")
|
||||
}
|
||||
|
||||
fn run(
|
||||
|
@ -53,12 +53,15 @@ pub fn create_default_context() -> EngineState {
|
||||
Math,
|
||||
MathAbs,
|
||||
MathAvg,
|
||||
MathMax,
|
||||
MathMin,
|
||||
Mkdir,
|
||||
Module,
|
||||
Mv,
|
||||
ParEach,
|
||||
Ps,
|
||||
Register,
|
||||
Range,
|
||||
Rm,
|
||||
RunPlugin,
|
||||
Select,
|
||||
|
@ -4,6 +4,7 @@ mod last;
|
||||
mod length;
|
||||
mod lines;
|
||||
mod par_each;
|
||||
mod range;
|
||||
mod select;
|
||||
mod where_;
|
||||
mod wrap;
|
||||
@ -14,6 +15,7 @@ pub use last::Last;
|
||||
pub use length::Length;
|
||||
pub use lines::Lines;
|
||||
pub use par_each::ParEach;
|
||||
pub use range::Range;
|
||||
pub use select::Select;
|
||||
pub use where_::Where;
|
||||
pub use wrap::Wrap;
|
||||
|
127
crates/nu-command/src/filters/range.rs
Normal file
127
crates/nu-command/src/filters/range.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use nu_engine::CallExt;
|
||||
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||
Value,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Range;
|
||||
|
||||
impl Command for Range {
|
||||
fn name(&self) -> &str {
|
||||
"range"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("range").optional(
|
||||
"rows",
|
||||
SyntaxShape::Range,
|
||||
"range of rows to return: Eg) 4..7 (=> from 4 to 7)",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Return only the selected rows."
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | range 4..5",
|
||||
description: "Get the last 2 items",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(5)],
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | range (-2)..",
|
||||
description: "Get the last 2 items",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(5)],
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | range (-3)..-2",
|
||||
description: "Get the next to last 2 items",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(3), Value::test_int(4)],
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let rows: nu_protocol::Range = call.req(engine_state, stack, 0)?;
|
||||
|
||||
let rows_from = get_range_val(rows.from);
|
||||
let rows_to = get_range_val(rows.to);
|
||||
|
||||
// only collect the input if we have any negative indices
|
||||
if rows_from < 0 || rows_to < 0 {
|
||||
let v: Vec<_> = input.into_iter().collect();
|
||||
let vlen: i64 = v.len() as i64;
|
||||
|
||||
let from = if rows_from < 0 {
|
||||
(vlen + rows_from) as usize
|
||||
} else {
|
||||
rows_from as usize
|
||||
};
|
||||
|
||||
let to = if rows_to < 0 {
|
||||
(vlen + rows_to) as usize
|
||||
} else if rows_to > v.len() as i64 {
|
||||
v.len()
|
||||
} else {
|
||||
rows_to as usize
|
||||
};
|
||||
|
||||
if from > to {
|
||||
Ok(PipelineData::Value(Value::Nothing { span: call.head }))
|
||||
} else {
|
||||
let iter = v.into_iter().skip(from).take(to - from + 1);
|
||||
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
|
||||
}
|
||||
} else {
|
||||
let from = rows_from as usize;
|
||||
let to = rows_to as usize;
|
||||
|
||||
if from > to {
|
||||
Ok(PipelineData::Value(Value::Nothing { span: call.head }))
|
||||
} else {
|
||||
let iter = input.into_iter().skip(from).take(to - from + 1);
|
||||
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_range_val(rows_val: Value) -> i64 {
|
||||
match rows_val {
|
||||
Value::Int { val: x, .. } => x,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(Range {})
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@ pub fn average(values: &[Value], head: &Span) -> Result<Value, ShellError> {
|
||||
span: Span::unknown(),
|
||||
},
|
||||
values.to_vec(),
|
||||
*head,
|
||||
)?;
|
||||
match total {
|
||||
Value::Filesize { val, span } => Ok(Value::Filesize {
|
||||
|
57
crates/nu-command/src/math/max.rs
Normal file
57
crates/nu-command/src/math/max.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use crate::math::reducers::{reducer_for, Reduce};
|
||||
use crate::math::utils::run_with_function;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
impl Command for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"math max"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("math max")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Finds the maximum within a list of numbers or tables"
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
run_with_function(call, input, maximum)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Find the maximum of list of numbers",
|
||||
example: "[-50 100 25] | math max",
|
||||
result: Some(Value::test_int(100)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maximum(values: &[Value], head: &Span) -> Result<Value, ShellError> {
|
||||
let max_func = reducer_for(Reduce::Maximum);
|
||||
max_func(Value::nothing(), values.to_vec(), *head)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
57
crates/nu-command/src/math/min.rs
Normal file
57
crates/nu-command/src/math/min.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use crate::math::reducers::{reducer_for, Reduce};
|
||||
use crate::math::utils::run_with_function;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
impl Command for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"math min"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("math min")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Finds the minimum within a list of numbers or tables"
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
run_with_function(call, input, minimum)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Get the minimum of a list of numbers",
|
||||
example: "[-50 100 25] | math min",
|
||||
result: Some(Value::test_int(-50)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn minimum(values: &[Value], head: &Span) -> Result<Value, ShellError> {
|
||||
let min_func = reducer_for(Reduce::Minimum);
|
||||
min_func(Value::nothing(), values.to_vec(), *head)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
mod abs;
|
||||
mod avg;
|
||||
pub mod command;
|
||||
mod max;
|
||||
mod min;
|
||||
mod reducers;
|
||||
mod utils;
|
||||
|
||||
pub use abs::SubCommand as MathAbs;
|
||||
pub use avg::SubCommand as MathAvg;
|
||||
pub use command::MathCommand as Math;
|
||||
pub use max::SubCommand as MathMax;
|
||||
pub use min::SubCommand as MathMin;
|
||||
|
@ -1,19 +1,73 @@
|
||||
use nu_protocol::{ShellError, Span, Value};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum Reduce {
|
||||
Summation,
|
||||
Minimum,
|
||||
Maximum,
|
||||
}
|
||||
|
||||
pub fn reducer_for(
|
||||
command: Reduce,
|
||||
) -> Box<dyn Fn(Value, Vec<Value>) -> Result<Value, ShellError> + Send + Sync + 'static> {
|
||||
pub type ReducerFunction =
|
||||
Box<dyn Fn(Value, Vec<Value>, Span) -> Result<Value, ShellError> + Send + Sync + 'static>;
|
||||
|
||||
pub fn reducer_for(command: Reduce) -> ReducerFunction {
|
||||
match command {
|
||||
Reduce::Summation => Box::new(|_, values| sum(values)),
|
||||
Reduce::Summation => Box::new(|_, values, head| sum(values, head)),
|
||||
Reduce::Minimum => Box::new(|_, values, head| min(values, head)),
|
||||
Reduce::Maximum => Box::new(|_, values, head| max(values, head)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sum(data: Vec<Value>) -> Result<Value, ShellError> {
|
||||
pub fn max(data: Vec<Value>, head: Span) -> Result<Value, ShellError> {
|
||||
let mut biggest = data
|
||||
.first()
|
||||
.ok_or_else(|| ShellError::UnsupportedInput("Empty input".to_string(), Span::unknown()))?
|
||||
.clone();
|
||||
|
||||
for value in &data {
|
||||
if let Some(result) = value.partial_cmp(&biggest) {
|
||||
if result == Ordering::Greater {
|
||||
biggest = value.clone();
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::OperatorMismatch {
|
||||
op_span: head,
|
||||
lhs_ty: biggest.get_type(),
|
||||
lhs_span: biggest.span()?,
|
||||
rhs_ty: value.get_type(),
|
||||
rhs_span: value.span()?,
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(biggest)
|
||||
}
|
||||
|
||||
pub fn min(data: Vec<Value>, head: Span) -> Result<Value, ShellError> {
|
||||
let mut smallest = data
|
||||
.first()
|
||||
.ok_or_else(|| ShellError::UnsupportedInput("Empty input".to_string(), Span::unknown()))?
|
||||
.clone();
|
||||
|
||||
for value in &data {
|
||||
if let Some(result) = value.partial_cmp(&smallest) {
|
||||
if result == Ordering::Less {
|
||||
smallest = value.clone();
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::OperatorMismatch {
|
||||
op_span: head,
|
||||
lhs_ty: smallest.get_type(),
|
||||
lhs_span: smallest.span()?,
|
||||
rhs_ty: value.get_type(),
|
||||
rhs_span: value.span()?,
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(smallest)
|
||||
}
|
||||
|
||||
pub fn sum(data: Vec<Value>, head: Span) -> Result<Value, ShellError> {
|
||||
let initial_value = data.get(0);
|
||||
|
||||
let mut acc = match initial_value {
|
||||
@ -42,7 +96,7 @@ pub fn sum(data: Vec<Value>) -> Result<Value, ShellError> {
|
||||
| Value::Float { .. }
|
||||
| Value::Filesize { .. }
|
||||
| Value::Duration { .. } => {
|
||||
let new_value = acc.add(acc.span().unwrap_or_else(|_| Span::unknown()), value);
|
||||
let new_value = acc.add(head, value);
|
||||
if new_value.is_err() {
|
||||
return new_value;
|
||||
}
|
||||
|
Reference in New Issue
Block a user