roll commands (#4437)

* roll commands

* removed repeated funtion
This commit is contained in:
Fernando Herrera 2022-02-12 11:11:54 +00:00 committed by GitHub
parent b4b7524206
commit 1fd7b9ac38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 529 additions and 0 deletions

View File

@ -94,6 +94,11 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
Reject,
Rename,
Reverse,
Roll,
RollDown,
RollUp,
RollLeft,
RollRight,
Rotate,
Select,
Shuffle,

View File

@ -31,6 +31,7 @@ mod reduce;
mod reject;
mod rename;
mod reverse;
mod roll;
mod rotate;
mod select;
mod shuffle;
@ -78,6 +79,7 @@ pub use reduce::Reduce;
pub use reject::Reject;
pub use rename::Rename;
pub use reverse::Reverse;
pub use roll::*;
pub use rotate::Rotate;
pub use select::Select;
pub use shuffle::Shuffle;

View File

@ -0,0 +1,101 @@
mod roll_;
mod roll_down;
mod roll_left;
mod roll_right;
mod roll_up;
use nu_protocol::{ShellError, Value};
pub use roll_::Roll;
pub use roll_down::RollDown;
pub use roll_left::RollLeft;
pub use roll_right::RollRight;
pub use roll_up::RollUp;
enum VerticalDirection {
Up,
Down,
}
fn vertical_rotate_value(
value: Value,
by: Option<usize>,
direction: VerticalDirection,
) -> Result<Value, ShellError> {
match value {
Value::List { mut vals, span } => {
let rotations = by.map(|n| n % vals.len()).unwrap_or(1);
let values = vals.as_mut_slice();
match direction {
VerticalDirection::Up => values.rotate_left(rotations),
VerticalDirection::Down => values.rotate_right(rotations),
}
Ok(Value::List {
vals: values.to_owned(),
span,
})
}
_ => Err(ShellError::TypeMismatch("list".to_string(), value.span()?)),
}
}
enum HorizontalDirection {
Left,
Right,
}
fn horizontal_rotate_value(
value: Value,
by: &Option<usize>,
cells_only: bool,
direction: &HorizontalDirection,
) -> Result<Value, ShellError> {
match value {
Value::Record {
mut cols,
mut vals,
span,
} => {
let rotations = by.map(|n| n % vals.len()).unwrap_or(1);
let columns = if cells_only {
cols
} else {
let columns = cols.as_mut_slice();
match direction {
HorizontalDirection::Right => columns.rotate_right(rotations),
HorizontalDirection::Left => columns.rotate_left(rotations),
}
columns.to_owned()
};
let values = vals.as_mut_slice();
match direction {
HorizontalDirection::Right => values.rotate_right(rotations),
HorizontalDirection::Left => values.rotate_left(rotations),
}
Ok(Value::Record {
cols: columns,
vals: values.to_owned(),
span,
})
}
Value::List { vals, span } => {
let values = vals
.into_iter()
.map(|value| horizontal_rotate_value(value, by, cells_only, direction))
.collect::<Result<Vec<Value>, ShellError>>()?;
Ok(Value::List { vals: values, span })
}
_ => Err(ShellError::TypeMismatch(
"record".to_string(),
value.span()?,
)),
}
}

View File

@ -0,0 +1,35 @@
use nu_engine::get_full_help;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, IntoPipelineData, PipelineData, ShellError, Signature, Value};
#[derive(Clone)]
pub struct Roll;
impl Command for Roll {
fn name(&self) -> &str {
"roll"
}
fn signature(&self) -> Signature {
Signature::build(self.name()).category(Category::Filters)
}
fn usage(&self) -> &str {
"Rolling commands for tables"
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
Ok(Value::String {
val: get_full_help(&Roll.signature(), &Roll.examples(), engine_state, stack),
span: call.head,
}
.into_pipeline_data())
}
}

View File

@ -0,0 +1,82 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
};
use super::{vertical_rotate_value, VerticalDirection};
#[derive(Clone)]
pub struct RollDown;
impl Command for RollDown {
fn name(&self) -> &str {
"roll down"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.named("by", SyntaxShape::Int, "Number of rows to roll", Some('b'))
.category(Category::Filters)
}
fn usage(&self) -> &str {
"Roll table rows down"
}
fn examples(&self) -> Vec<Example> {
let columns = vec!["a".to_string(), "b".to_string()];
vec![Example {
description: "Rolls rows down",
example: "[[a b]; [1 2] [3 4] [5 6]] | roll down",
result: Some(Value::List {
vals: vec![
Value::Record {
cols: columns.clone(),
vals: vec![Value::test_int(5), Value::test_int(6)],
span: Span::test_data(),
},
Value::Record {
cols: columns.clone(),
vals: vec![Value::test_int(1), Value::test_int(2)],
span: Span::test_data(),
},
Value::Record {
cols: columns,
vals: vec![Value::test_int(3), Value::test_int(4)],
span: Span::test_data(),
},
],
span: Span::test_data(),
}),
}]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, ShellError> {
let by: Option<usize> = call.get_flag(engine_state, stack, "by")?;
let value = input.into_value(call.head);
let rotated_value = vertical_rotate_value(value, by, VerticalDirection::Down)?;
Ok(rotated_value.into_pipeline_data())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(RollDown {})
}
}

View File

@ -0,0 +1,111 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
};
use super::{horizontal_rotate_value, HorizontalDirection};
#[derive(Clone)]
pub struct RollLeft;
impl Command for RollLeft {
fn name(&self) -> &str {
"roll left"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.named(
"by",
SyntaxShape::Int,
"Number of columns to roll",
Some('b'),
)
.switch(
"cells-only",
"rotates columns leaving headers fixed",
Some('c'),
)
.category(Category::Filters)
}
fn usage(&self) -> &str {
"Roll table columns left"
}
fn examples(&self) -> Vec<Example> {
let columns = vec!["a".to_string(), "b".to_string(), "c".to_string()];
let rotated_columns = vec!["b".to_string(), "c".to_string(), "a".to_string()];
vec![
Example {
description: "Rolls columns to the left",
example: "[[a b c]; [1 2 3] [4 5 6]] | roll left",
result: Some(Value::List {
vals: vec![
Value::Record {
cols: rotated_columns.clone(),
vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(1)],
span: Span::test_data(),
},
Value::Record {
cols: rotated_columns,
vals: vec![Value::test_int(5), Value::test_int(6), Value::test_int(4)],
span: Span::test_data(),
},
],
span: Span::test_data(),
}),
},
Example {
description: "Rolls columns to the left with fixed headers",
example: "[[a b c]; [1 2 3] [4 5 6]] | roll left --cells-only",
result: Some(Value::List {
vals: vec![
Value::Record {
cols: columns.clone(),
vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(1)],
span: Span::test_data(),
},
Value::Record {
cols: columns,
vals: vec![Value::test_int(5), Value::test_int(6), Value::test_int(4)],
span: Span::test_data(),
},
],
span: Span::test_data(),
}),
},
]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, ShellError> {
let by: Option<usize> = call.get_flag(engine_state, stack, "by")?;
let cells_only = call.has_flag("cells-only");
let value = input.into_value(call.head);
let rotated_value =
horizontal_rotate_value(value, &by, cells_only, &HorizontalDirection::Left)?;
Ok(rotated_value.into_pipeline_data())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(RollLeft {})
}
}

View File

@ -0,0 +1,111 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
};
use super::{horizontal_rotate_value, HorizontalDirection};
#[derive(Clone)]
pub struct RollRight;
impl Command for RollRight {
fn name(&self) -> &str {
"roll right"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.named(
"by",
SyntaxShape::Int,
"Number of columns to roll",
Some('b'),
)
.switch(
"cells-only",
"rotates columns leaving headers fixed",
Some('c'),
)
.category(Category::Filters)
}
fn usage(&self) -> &str {
"Roll table columns right"
}
fn examples(&self) -> Vec<Example> {
let columns = vec!["a".to_string(), "b".to_string(), "c".to_string()];
let rotated_columns = vec!["c".to_string(), "a".to_string(), "b".to_string()];
vec![
Example {
description: "Rolls columns to the right",
example: "[[a b c]; [1 2 3] [4 5 6]] | roll right",
result: Some(Value::List {
vals: vec![
Value::Record {
cols: rotated_columns.clone(),
vals: vec![Value::test_int(3), Value::test_int(1), Value::test_int(2)],
span: Span::test_data(),
},
Value::Record {
cols: rotated_columns,
vals: vec![Value::test_int(6), Value::test_int(4), Value::test_int(5)],
span: Span::test_data(),
},
],
span: Span::test_data(),
}),
},
Example {
description: "Rolls columns to the right with fixed headers",
example: "[[a b c]; [1 2 3] [4 5 6]] | roll right --cells-only",
result: Some(Value::List {
vals: vec![
Value::Record {
cols: columns.clone(),
vals: vec![Value::test_int(3), Value::test_int(1), Value::test_int(2)],
span: Span::test_data(),
},
Value::Record {
cols: columns,
vals: vec![Value::test_int(6), Value::test_int(4), Value::test_int(5)],
span: Span::test_data(),
},
],
span: Span::test_data(),
}),
},
]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, ShellError> {
let by: Option<usize> = call.get_flag(engine_state, stack, "by")?;
let cells_only = call.has_flag("cells-only");
let value = input.into_value(call.head);
let rotated_value =
horizontal_rotate_value(value, &by, cells_only, &HorizontalDirection::Right)?;
Ok(rotated_value.into_pipeline_data())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(RollRight {})
}
}

View File

@ -0,0 +1,82 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
};
use super::{vertical_rotate_value, VerticalDirection};
#[derive(Clone)]
pub struct RollUp;
impl Command for RollUp {
fn name(&self) -> &str {
"roll up"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.named("by", SyntaxShape::Int, "Number of rows to roll", Some('b'))
.category(Category::Filters)
}
fn usage(&self) -> &str {
"Roll table rows up"
}
fn examples(&self) -> Vec<Example> {
let columns = vec!["a".to_string(), "b".to_string()];
vec![Example {
description: "Rolls rows up",
example: "[[a b]; [1 2] [3 4] [5 6]] | roll up",
result: Some(Value::List {
vals: vec![
Value::Record {
cols: columns.clone(),
vals: vec![Value::test_int(3), Value::test_int(4)],
span: Span::test_data(),
},
Value::Record {
cols: columns.clone(),
vals: vec![Value::test_int(5), Value::test_int(6)],
span: Span::test_data(),
},
Value::Record {
cols: columns,
vals: vec![Value::test_int(1), Value::test_int(2)],
span: Span::test_data(),
},
],
span: Span::test_data(),
}),
}]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, ShellError> {
let by: Option<usize> = call.get_flag(engine_state, stack, "by")?;
let value = input.into_value(call.head);
let rotated_value = vertical_rotate_value(value, by, VerticalDirection::Up)?;
Ok(rotated_value.into_pipeline_data())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(RollUp {})
}
}