mirror of
https://github.com/nushell/nushell.git
synced 2024-12-24 07:59:21 +01:00
Make to text
stream ListStreams (#7577)
This PR changes `to text` so that when given a `ListStream`, it streams the incoming values instead of collecting them all first. The easiest way to observe/verify this PR is to convert a list to a very slow `ListStream` with `each`: ```bash ls | get name | each {|n| sleep 1sec; $n} | to text ``` The `to text` output will appear 1 item at a time.
This commit is contained in:
parent
6fc5244439
commit
9364bad625
@ -3,7 +3,7 @@ use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
format_duration, format_filesize_from_conf, Category, Config, Example, IntoPipelineData,
|
||||
PipelineData, ShellError, Signature, Type, Value,
|
||||
ListStream, PipelineData, RawStream, ShellError, Signature, Type, Value,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -40,6 +40,26 @@ impl Command for ToText {
|
||||
"\n"
|
||||
};
|
||||
|
||||
if let PipelineData::ListStream(stream, _) = input {
|
||||
Ok(PipelineData::ExternalStream {
|
||||
stdout: Some(RawStream::new(
|
||||
Box::new(ListStreamIterator {
|
||||
stream,
|
||||
separator: line_ending.into(),
|
||||
config: config.clone(),
|
||||
}),
|
||||
engine_state.ctrlc.clone(),
|
||||
span,
|
||||
)),
|
||||
stderr: None,
|
||||
exit_code: None,
|
||||
span,
|
||||
metadata: None,
|
||||
trim_end_newline: false,
|
||||
})
|
||||
} else {
|
||||
// FIXME: don't collect! stream the output wherever possible!
|
||||
// Even if the data is collected when it arrives at `to text`, we should be able to stream it out
|
||||
let collected_input = local_into_string(input.into_value(span), line_ending, config);
|
||||
|
||||
Ok(Value::String {
|
||||
@ -48,6 +68,7 @@ impl Command for ToText {
|
||||
}
|
||||
.into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
@ -70,6 +91,26 @@ impl Command for ToText {
|
||||
}
|
||||
}
|
||||
|
||||
struct ListStreamIterator {
|
||||
stream: ListStream,
|
||||
separator: String,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
impl Iterator for ListStreamIterator {
|
||||
type Item = Result<Vec<u8>, ShellError>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(item) = self.stream.next() {
|
||||
let mut string = local_into_string(item, &self.separator, &self.config);
|
||||
string.push_str(&self.separator);
|
||||
Some(Ok(string.as_bytes().to_vec()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn local_into_string(value: Value, separator: &str, config: &Config) -> String {
|
||||
match value {
|
||||
Value::Bool { val, .. } => val.to_string(),
|
||||
|
@ -90,6 +90,7 @@ mod split_row;
|
||||
mod str_;
|
||||
mod table;
|
||||
mod take;
|
||||
mod to_text;
|
||||
mod touch;
|
||||
mod transpose;
|
||||
mod try_;
|
||||
|
19
crates/nu-command/tests/commands/to_text.rs
Normal file
19
crates/nu-command/tests/commands/to_text.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use nu_test_support::nu;
|
||||
|
||||
#[test]
|
||||
fn list_to_text() {
|
||||
let actual = nu!(r#"["foo" "bar" "baz"] | to text"#);
|
||||
|
||||
// these actually have newlines between them in the real world but nu! strips newlines, grr
|
||||
assert_eq!(actual.out, "foobarbaz");
|
||||
}
|
||||
|
||||
// the output should be the same when `to text` gets a ListStream instead of a Value::List
|
||||
#[test]
|
||||
fn list_stream_to_text() {
|
||||
// use `each` to convert the list to a ListStream
|
||||
let actual = nu!(r#"["foo" "bar" "baz"] | each {|i| $i} | to text"#);
|
||||
|
||||
// these actually have newlines between them in the real world but nu! strips newlines, grr
|
||||
assert_eq!(actual.out, "foobarbaz");
|
||||
}
|
Loading…
Reference in New Issue
Block a user