diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 1dcc43e93d..4be83f7629 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -119,6 +119,7 @@ pub fn create_default_context() -> EngineState { SkipWhile, Sort, SortBy, + SplitList, Transpose, Uniq, Upsert, diff --git a/crates/nu-command/src/strings/split/list.rs b/crates/nu-command/src/strings/split/list.rs new file mode 100644 index 0000000000..7c362d4c5f --- /dev/null +++ b/crates/nu-command/src/strings/split/list.rs @@ -0,0 +1,130 @@ +use nu_engine::CallExt; +use nu_protocol::{ + ast::Call, + engine::{Command, EngineState, Stack}, + Category, Example, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Value, +}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "split list" + } + + fn signature(&self) -> Signature { + Signature::build("split list") + .required( + "separator", + SyntaxShape::Any, + "the value that denotes what separates the list", + ) + .category(Category::Filters) + } + + fn usage(&self) -> &str { + "Split a list into multiple lists using a separator" + } + + fn search_terms(&self) -> Vec<&str> { + vec!["list", "separate", "divide"] + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + split_list(engine_state, stack, call, input) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Split a list of chars into two lists", + example: "[a, b, c, d, e, f, g] | split list d", + result: Some(Value::List { + vals: vec![ + Value::List { + vals: vec![ + Value::test_string("a"), + Value::test_string("b"), + Value::test_string("c"), + ], + span: Span::test_data(), + }, + Value::List { + vals: vec![ + Value::test_string("e"), + Value::test_string("f"), + Value::test_string("g"), + ], + span: Span::test_data(), + }, + ], + span: Span::test_data(), + }), + }, + Example { + description: "Split a list of lists into two lists of lists", + example: "[[1,2], [2,3], [3,4]] | split list [2,3]", + result: Some(Value::List { + vals: vec![ + Value::List { + vals: vec![Value::List { + vals: vec![Value::test_int(1), Value::test_int(2)], + span: Span::test_data(), + }], + span: Span::test_data(), + }, + Value::List { + vals: vec![Value::List { + vals: vec![Value::test_int(3), Value::test_int(4)], + span: Span::test_data(), + }], + span: Span::test_data(), + }, + ], + span: Span::test_data(), + }), + }, + ] + } +} + +fn split_list( + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, +) -> Result { + let separator: Value = call.req(engine_state, stack, 0)?; + let mut temp_list = Vec::new(); + let mut returned_list = Vec::new(); + let iter = input.into_interruptible_iter(engine_state.ctrlc.clone()); + for val in iter { + if val == separator && !temp_list.is_empty() { + returned_list.push(Value::List { + vals: temp_list.clone(), + span: call.head, + }); + temp_list = Vec::new(); + } else { + temp_list.push(val); + } + } + if !temp_list.is_empty() { + returned_list.push(Value::List { + vals: temp_list.clone(), + span: call.head, + }); + } + Ok(Value::List { + vals: returned_list, + span: call.head, + } + .into_pipeline_data()) +} diff --git a/crates/nu-command/src/strings/split/mod.rs b/crates/nu-command/src/strings/split/mod.rs index c6e6da0171..8d9c638f0b 100644 --- a/crates/nu-command/src/strings/split/mod.rs +++ b/crates/nu-command/src/strings/split/mod.rs @@ -1,9 +1,11 @@ pub mod chars; pub mod column; pub mod command; +pub mod list; pub mod row; pub use chars::SubCommand as SplitChars; pub use column::SubCommand as SplitColumn; pub use command::SplitCommand as Split; +pub use list::SubCommand as SplitList; pub use row::SubCommand as SplitRow;