From cb7ac9199d1f306135e71d3a34f9877972c1836a Mon Sep 17 00:00:00 2001 From: Firegem Date: Tue, 24 Jun 2025 19:17:33 -0400 Subject: [PATCH] Stream lazy `default` output (#15955) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was brought up in the Discord that `default { open -r foo.txt }` results in a string instead of streaming output. This changes `default` such that closures now stream when given simple input. # Description If the value isn't expected to be cached, `default` just runs the closure without caching the value, which allows its output to be streamed # User-Facing Changes # Tests + Formatting 👍 # After Submitting --- crates/nu-command/src/filters/default.rs | 14 ++++++++++---- crates/nu-command/tests/commands/default.rs | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/nu-command/src/filters/default.rs b/crates/nu-command/src/filters/default.rs index a993d3efa9..5d0d3580ab 100644 --- a/crates/nu-command/src/filters/default.rs +++ b/crates/nu-command/src/filters/default.rs @@ -213,7 +213,7 @@ fn default( || (default_when_empty && matches!(input, PipelineData::Value(ref value, _) if value.is_empty())) { - default_value.pipeline_data() + default_value.single_run_pipeline_data() } else if default_when_empty && matches!(input, PipelineData::ListStream(..)) { let PipelineData::ListStream(ls, metadata) = input else { unreachable!() @@ -221,7 +221,7 @@ fn default( let span = ls.span(); let mut stream = ls.into_inner().peekable(); if stream.peek().is_none() { - return default_value.pipeline_data(); + return default_value.single_run_pipeline_data(); } // stream's internal state already preserves the original signals config, so if this @@ -278,8 +278,14 @@ impl DefaultValue { } } - fn pipeline_data(&mut self) -> Result { - self.value().map(|x| x.into_pipeline_data()) + /// Used when we know the value won't need to be cached to allow streaming. + fn single_run_pipeline_data(self) -> Result { + match self { + DefaultValue::Uncalculated(mut closure) => { + closure.item.run_with_input(PipelineData::Empty) + } + DefaultValue::Calculated(val) => Ok(val.into_pipeline_data()), + } } } diff --git a/crates/nu-command/tests/commands/default.rs b/crates/nu-command/tests/commands/default.rs index 75acf6d187..c419030be3 100644 --- a/crates/nu-command/tests/commands/default.rs +++ b/crates/nu-command/tests/commands/default.rs @@ -244,3 +244,9 @@ fn return_closure_value() { let actual = nu!(r#"null | default { {||} }"#); assert!(actual.out.starts_with("closure")); } + +#[test] +fn lazy_output_streams() { + let actual = nu!(r#"default { nu --testbin cococo 'hello' } | describe"#); + assert!(actual.out.contains("byte stream")); +}