diff --git a/crates/nu-command/src/generators/seq.rs b/crates/nu-command/src/generators/seq.rs index 4eb0cc3b25..99c40d56b9 100644 --- a/crates/nu-command/src/generators/seq.rs +++ b/crates/nu-command/src/generators/seq.rs @@ -140,30 +140,30 @@ pub fn run_seq( if !contains_decimals { // integers only Ok(PipelineData::ListStream( - nu_protocol::ListStream { - stream: Box::new(IntSeq { + nu_protocol::ListStream::from_stream( + IntSeq { count: first as i64, step: step as i64, last: last as i64, span, - }), - ctrlc: engine_state.ctrlc.clone(), - }, + }, + engine_state.ctrlc.clone(), + ), None, )) } else { // floats Ok(PipelineData::ListStream( - nu_protocol::ListStream { - stream: Box::new(FloatSeq { + nu_protocol::ListStream::from_stream( + FloatSeq { first, step, last, index: 0, span, - }), - ctrlc: engine_state.ctrlc.clone(), - }, + }, + engine_state.ctrlc.clone(), + ), None, )) } diff --git a/crates/nu-protocol/src/pipeline_data.rs b/crates/nu-protocol/src/pipeline_data.rs index 8d2e2b6d0b..5ebb67a49a 100644 --- a/crates/nu-protocol/src/pipeline_data.rs +++ b/crates/nu-protocol/src/pipeline_data.rs @@ -270,25 +270,19 @@ impl PipelineData { match self { PipelineData::Value(val, metadata) => match val { Value::List { vals, .. } => Ok(PipelineIterator(PipelineData::ListStream( - ListStream { - stream: Box::new(vals.into_iter()), - ctrlc: None, - }, + ListStream::from_stream(vals.into_iter(), None), metadata, ))), Value::Binary { val, .. } => Ok(PipelineIterator(PipelineData::ListStream( - ListStream { - stream: Box::new(val.into_iter().map(move |x| Value::int(x as i64, span))), - ctrlc: None, - }, + ListStream::from_stream( + val.into_iter().map(move |x| Value::int(x as i64, span)), + None, + ), metadata, ))), Value::Range { val, .. } => match val.into_range_iter(None) { Ok(iter) => Ok(PipelineIterator(PipelineData::ListStream( - ListStream { - stream: Box::new(iter), - ctrlc: None, - }, + ListStream::from_stream(iter, None), metadata, ))), Err(error) => Err(error), @@ -822,25 +816,19 @@ impl IntoIterator for PipelineData { let span = v.span(); match v { Value::List { vals, .. } => PipelineIterator(PipelineData::ListStream( - ListStream { - stream: Box::new(vals.into_iter()), - ctrlc: None, - }, + ListStream::from_stream(vals.into_iter(), None), metadata, )), Value::Range { val, .. } => match val.into_range_iter(None) { Ok(iter) => PipelineIterator(PipelineData::ListStream( - ListStream { - stream: Box::new(iter), - ctrlc: None, - }, + ListStream::from_stream(iter, None), metadata, )), Err(error) => PipelineIterator(PipelineData::ListStream( - ListStream { - stream: Box::new(std::iter::once(Value::error(error, span))), - ctrlc: None, - }, + ListStream::from_stream( + std::iter::once(Value::error(error, span)), + None, + ), metadata, )), }, @@ -965,10 +953,7 @@ where { fn into_pipeline_data(self, ctrlc: Option>) -> PipelineData { PipelineData::ListStream( - ListStream { - stream: Box::new(self.into_iter().map(Into::into)), - ctrlc, - }, + ListStream::from_stream(self.into_iter().map(Into::into), ctrlc), None, ) } @@ -979,10 +964,7 @@ where ctrlc: Option>, ) -> PipelineData { PipelineData::ListStream( - ListStream { - stream: Box::new(self.into_iter().map(Into::into)), - ctrlc, - }, + ListStream::from_stream(self.into_iter().map(Into::into), ctrlc), metadata.into(), ) } diff --git a/crates/nu-protocol/src/value/stream.rs b/crates/nu-protocol/src/value/stream.rs index 13bc379444..4118b24eef 100644 --- a/crates/nu-protocol/src/value/stream.rs +++ b/crates/nu-protocol/src/value/stream.rs @@ -184,6 +184,7 @@ impl Iterator for RawStream { pub struct ListStream { pub stream: Box + Send + 'static>, pub ctrlc: Option>, + first_guard: bool, } impl ListStream { @@ -209,6 +210,7 @@ impl ListStream { ListStream { stream: Box::new(input), ctrlc, + first_guard: true, } } } @@ -223,6 +225,17 @@ impl Iterator for ListStream { type Item = Value; fn next(&mut self) -> Option { + // We need to check `first_guard` to guarantee that it always have something to return in + // underlying stream. + // + // A realworld example is running an external commands, which have an `exit_code` + // ListStream. + // When we press ctrl-c, the external command receives the signal too, if we don't have + // `first_guard`, the `exit_code` ListStream will return Nothing, which is not expected + if self.first_guard { + self.first_guard = false; + return self.stream.next(); + } if nu_utils::ctrl_c::was_pressed(&self.ctrlc) { None } else {