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,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
format_duration, format_filesize_from_conf, Category, Config, Example, IntoPipelineData,
|
format_duration, format_filesize_from_conf, Category, Config, Example, IntoPipelineData,
|
||||||
PipelineData, ShellError, Signature, Type, Value,
|
ListStream, PipelineData, RawStream, ShellError, Signature, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -40,13 +40,34 @@ impl Command for ToText {
|
|||||||
"\n"
|
"\n"
|
||||||
};
|
};
|
||||||
|
|
||||||
let collected_input = local_into_string(input.into_value(span), line_ending, config);
|
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 {
|
Ok(Value::String {
|
||||||
val: collected_input,
|
val: collected_input,
|
||||||
span,
|
span,
|
||||||
|
}
|
||||||
|
.into_pipeline_data())
|
||||||
}
|
}
|
||||||
.into_pipeline_data())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -58,18 +79,38 @@ impl Command for ToText {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Outputs external data as simple text",
|
description: "Outputs external data as simple text",
|
||||||
example: "git help -a | lines | find -r '^ ' | to text",
|
example: "git help -a | lines | find -r '^ ' | to text",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Outputs records as simple text",
|
description: "Outputs records as simple text",
|
||||||
example: "ls | to text",
|
example: "ls | to text",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
fn local_into_string(value: Value, separator: &str, config: &Config) -> String {
|
||||||
match value {
|
match value {
|
||||||
Value::Bool { val, .. } => val.to_string(),
|
Value::Bool { val, .. } => val.to_string(),
|
||||||
|
@ -90,6 +90,7 @@ mod split_row;
|
|||||||
mod str_;
|
mod str_;
|
||||||
mod table;
|
mod table;
|
||||||
mod take;
|
mod take;
|
||||||
|
mod to_text;
|
||||||
mod touch;
|
mod touch;
|
||||||
mod transpose;
|
mod transpose;
|
||||||
mod try_;
|
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