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()) }