2022-04-26 01:44:57 +02:00
|
|
|
use crate::{
|
|
|
|
ast::{Call, PathMember},
|
2022-05-01 22:40:46 +02:00
|
|
|
engine::{EngineState, Stack, StateWorkingSet},
|
|
|
|
format_error, Config, ListStream, RawStream, ShellError, Span, Value,
|
2022-04-26 01:44:57 +02:00
|
|
|
};
|
2022-07-02 16:54:49 +02:00
|
|
|
use nu_utils::{stderr_write_all_and_flush, stdout_write_all_and_flush};
|
2022-05-17 20:28:18 +02:00
|
|
|
use std::sync::{atomic::AtomicBool, Arc};
|
2023-01-28 21:40:52 +01:00
|
|
|
use std::thread;
|
2021-10-25 06:01:02 +02:00
|
|
|
|
2023-01-08 22:51:51 +01:00
|
|
|
const LINE_ENDING_PATTERN: &[char] = &['\r', '\n'];
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
|
2021-11-02 20:53:48 +01:00
|
|
|
/// The foundational abstraction for input and output to commands
|
|
|
|
///
|
|
|
|
/// This represents either a single Value or a stream of values coming into the command or leaving a command.
|
|
|
|
///
|
|
|
|
/// A note on implementation:
|
|
|
|
///
|
|
|
|
/// We've tried a few variations of this structure. Listing these below so we have a record.
|
|
|
|
///
|
|
|
|
/// * We tried always assuming a stream in Nushell. This was a great 80% solution, but it had some rough edges.
|
|
|
|
/// Namely, how do you know the difference between a single string and a list of one string. How do you know
|
|
|
|
/// when to flatten the data given to you from a data source into the stream or to keep it as an unflattened
|
|
|
|
/// list?
|
2021-11-03 01:26:09 +01:00
|
|
|
///
|
2021-11-02 20:53:48 +01:00
|
|
|
/// * We tried putting the stream into Value. This had some interesting properties as now commands "just worked
|
2021-11-03 01:26:09 +01:00
|
|
|
/// on values", but lead to a few unfortunate issues.
|
|
|
|
///
|
|
|
|
/// The first is that you can't easily clone Values in a way that felt largely immutable. For example, if
|
|
|
|
/// you cloned a Value which contained a stream, and in one variable drained some part of it, then the second
|
|
|
|
/// variable would see different values based on what you did to the first.
|
|
|
|
///
|
|
|
|
/// To make this kind of mutation thread-safe, we would have had to produce a lock for the stream, which in
|
|
|
|
/// practice would have meant always locking the stream before reading from it. But more fundamentally, it
|
|
|
|
/// felt wrong in practice that observation of a value at runtime could affect other values which happen to
|
|
|
|
/// alias the same stream. By separating these, we don't have this effect. Instead, variables could get
|
|
|
|
/// concrete list values rather than streams, and be able to view them without non-local effects.
|
|
|
|
///
|
2021-11-02 20:53:48 +01:00
|
|
|
/// * A balance of the two approaches is what we've landed on: Values are thread-safe to pass, and we can stream
|
|
|
|
/// them into any sources. Streams are still available to model the infinite streams approach of original
|
|
|
|
/// Nushell.
|
2021-11-28 20:35:02 +01:00
|
|
|
#[derive(Debug)]
|
2021-10-25 06:01:02 +02:00
|
|
|
pub enum PipelineData {
|
2023-02-11 22:35:48 +01:00
|
|
|
// Note: the PipelineMetadata is boxed everywhere because the DataSource::Profiling caused
|
|
|
|
// stack overflow on Windows CI when testing virtualenv
|
|
|
|
Value(Value, Option<Box<PipelineMetadata>>),
|
|
|
|
ListStream(ListStream, Option<Box<PipelineMetadata>>),
|
2022-02-25 20:51:31 +01:00
|
|
|
ExternalStream {
|
2022-03-08 02:17:33 +01:00
|
|
|
stdout: Option<RawStream>,
|
2022-02-25 20:51:31 +01:00
|
|
|
stderr: Option<RawStream>,
|
|
|
|
exit_code: Option<ListStream>,
|
|
|
|
span: Span,
|
2023-02-11 22:35:48 +01:00
|
|
|
metadata: Option<Box<PipelineMetadata>>,
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
trim_end_newline: bool,
|
2022-02-25 20:51:31 +01:00
|
|
|
},
|
2022-12-07 19:31:57 +01:00
|
|
|
Empty,
|
2021-12-02 06:59:10 +01:00
|
|
|
}
|
|
|
|
|
2021-12-24 01:16:50 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2021-12-02 06:59:10 +01:00
|
|
|
pub struct PipelineMetadata {
|
|
|
|
pub data_source: DataSource,
|
|
|
|
}
|
|
|
|
|
2021-12-24 01:16:50 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2021-12-02 06:59:10 +01:00
|
|
|
pub enum DataSource {
|
|
|
|
Ls,
|
2022-11-15 18:12:56 +01:00
|
|
|
HtmlThemes,
|
2023-02-11 22:35:48 +01:00
|
|
|
Profiling(Vec<Value>),
|
2021-10-25 06:01:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PipelineData {
|
2023-02-11 22:35:48 +01:00
|
|
|
pub fn new_with_metadata(metadata: Option<Box<PipelineMetadata>>, span: Span) -> PipelineData {
|
2022-01-24 02:23:03 +01:00
|
|
|
PipelineData::Value(Value::Nothing { span }, metadata)
|
|
|
|
}
|
|
|
|
|
2022-12-07 19:31:57 +01:00
|
|
|
pub fn empty() -> PipelineData {
|
|
|
|
PipelineData::Empty
|
|
|
|
}
|
|
|
|
|
2023-02-11 22:35:48 +01:00
|
|
|
pub fn metadata(&self) -> Option<Box<PipelineMetadata>> {
|
2021-12-24 01:16:50 +01:00
|
|
|
match self {
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::ListStream(_, x) => x.clone(),
|
2022-02-25 20:51:31 +01:00
|
|
|
PipelineData::ExternalStream { metadata: x, .. } => x.clone(),
|
2021-12-24 01:16:50 +01:00
|
|
|
PipelineData::Value(_, x) => x.clone(),
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::Empty => None,
|
2021-12-24 01:16:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-11 22:35:48 +01:00
|
|
|
pub fn set_metadata(mut self, metadata: Option<Box<PipelineMetadata>>) -> Self {
|
2021-12-29 12:17:20 +01:00
|
|
|
match &mut self {
|
|
|
|
PipelineData::ListStream(_, x) => *x = metadata,
|
2022-02-25 20:51:31 +01:00
|
|
|
PipelineData::ExternalStream { metadata: x, .. } => *x = metadata,
|
2021-12-29 12:17:20 +01:00
|
|
|
PipelineData::Value(_, x) => *x = metadata,
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::Empty => {}
|
2021-12-29 12:17:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-01-31 13:52:05 +01:00
|
|
|
pub fn is_nothing(&self) -> bool {
|
|
|
|
matches!(self, PipelineData::Value(Value::Nothing { .. }, ..))
|
2022-12-07 19:31:57 +01:00
|
|
|
|| matches!(self, PipelineData::Empty)
|
2022-01-31 13:52:05 +01:00
|
|
|
}
|
|
|
|
|
2022-11-14 00:15:27 +01:00
|
|
|
/// PipelineData doesn't always have a Span, but we can try!
|
|
|
|
pub fn span(&self) -> Option<Span> {
|
|
|
|
match self {
|
|
|
|
PipelineData::ListStream(..) => None,
|
|
|
|
PipelineData::ExternalStream { span, .. } => Some(*span),
|
|
|
|
PipelineData::Value(v, _) => v.span().ok(),
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::Empty => None,
|
2022-11-14 00:15:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-06 06:50:33 +01:00
|
|
|
pub fn into_value(self, span: Span) -> Value {
|
2021-10-25 06:01:02 +02:00
|
|
|
match self {
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::Empty => Value::nothing(span),
|
2021-12-19 08:46:13 +01:00
|
|
|
PipelineData::Value(Value::Nothing { .. }, ..) => Value::nothing(span),
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(v, ..) => v,
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::ListStream(s, ..) => Value::List {
|
2022-09-01 01:09:40 +02:00
|
|
|
vals: s.collect(),
|
2021-11-06 06:50:33 +01:00
|
|
|
span, // FIXME?
|
2021-10-25 06:01:02 +02:00
|
|
|
},
|
2022-03-10 13:32:46 +01:00
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: None,
|
|
|
|
exit_code,
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
// Make sure everything has finished
|
|
|
|
if let Some(exit_code) = exit_code {
|
|
|
|
let _: Vec<_> = exit_code.into_iter().collect();
|
|
|
|
}
|
|
|
|
Value::Nothing { span }
|
|
|
|
}
|
2022-03-08 02:17:33 +01:00
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: Some(mut s),
|
2022-03-10 13:32:46 +01:00
|
|
|
exit_code,
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
trim_end_newline,
|
2022-03-08 02:17:33 +01:00
|
|
|
..
|
|
|
|
} => {
|
2022-01-28 19:32:33 +01:00
|
|
|
let mut items = vec![];
|
|
|
|
|
|
|
|
for val in &mut s {
|
|
|
|
match val {
|
|
|
|
Ok(val) => {
|
|
|
|
items.push(val);
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
return Value::Error { error: e };
|
|
|
|
}
|
2021-12-24 08:22:11 +01:00
|
|
|
}
|
|
|
|
}
|
2021-12-24 20:24:55 +01:00
|
|
|
|
2022-03-10 13:32:46 +01:00
|
|
|
// Make sure everything has finished
|
|
|
|
if let Some(exit_code) = exit_code {
|
|
|
|
let _: Vec<_> = exit_code.into_iter().collect();
|
|
|
|
}
|
|
|
|
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
// NOTE: currently trim-end-newline only handles for string output.
|
|
|
|
// For binary, user might need origin data.
|
2022-01-28 19:32:33 +01:00
|
|
|
if s.is_binary {
|
|
|
|
let mut output = vec![];
|
|
|
|
for item in items {
|
|
|
|
match item.as_binary() {
|
|
|
|
Ok(item) => {
|
|
|
|
output.extend(item);
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
return Value::Error { error: err };
|
|
|
|
}
|
|
|
|
}
|
2021-12-24 20:24:55 +01:00
|
|
|
}
|
|
|
|
|
2022-01-28 19:32:33 +01:00
|
|
|
Value::Binary {
|
|
|
|
val: output,
|
|
|
|
span, // FIXME?
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let mut output = String::new();
|
|
|
|
for item in items {
|
|
|
|
match item.as_string() {
|
|
|
|
Ok(s) => output.push_str(&s),
|
|
|
|
Err(err) => {
|
|
|
|
return Value::Error { error: err };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
if trim_end_newline {
|
2023-01-08 22:51:51 +01:00
|
|
|
output.truncate(output.trim_end_matches(LINE_ENDING_PATTERN).len())
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
}
|
2022-01-28 19:32:33 +01:00
|
|
|
Value::String {
|
|
|
|
val: output,
|
|
|
|
span, // FIXME?
|
|
|
|
}
|
2021-12-24 20:24:55 +01:00
|
|
|
}
|
|
|
|
}
|
2021-10-25 06:01:02 +02:00
|
|
|
}
|
|
|
|
}
|
2021-10-25 06:24:10 +02:00
|
|
|
|
last, skip, drop, take until, take while, skip until, skip while, where, reverse, shuffle, append, prepend and sort-by raise error when given non-lists (#7623)
Closes https://github.com/nushell/nushell/issues/6941
2022-12-31 12:35:12 +01:00
|
|
|
/// Try convert from self into iterator
|
|
|
|
///
|
|
|
|
/// It returns Err if the `self` cannot be converted to an iterator.
|
|
|
|
pub fn into_iter_strict(self, span: Span) -> Result<PipelineIterator, ShellError> {
|
|
|
|
match self {
|
|
|
|
PipelineData::Value(val, metadata) => match val {
|
|
|
|
Value::List { vals, .. } => Ok(PipelineIterator(PipelineData::ListStream(
|
|
|
|
ListStream {
|
|
|
|
stream: Box::new(vals.into_iter()),
|
|
|
|
ctrlc: None,
|
|
|
|
},
|
|
|
|
metadata,
|
|
|
|
))),
|
|
|
|
Value::Binary { val, span } => Ok(PipelineIterator(PipelineData::ListStream(
|
|
|
|
ListStream {
|
|
|
|
stream: Box::new(val.into_iter().map(move |x| Value::int(x as i64, span))),
|
|
|
|
ctrlc: None,
|
|
|
|
},
|
|
|
|
metadata,
|
|
|
|
))),
|
|
|
|
Value::Range { val, .. } => match val.into_range_iter(None) {
|
|
|
|
Ok(iter) => Ok(PipelineIterator(PipelineData::ListStream(
|
|
|
|
ListStream {
|
|
|
|
stream: Box::new(iter),
|
|
|
|
ctrlc: None,
|
|
|
|
},
|
|
|
|
metadata,
|
|
|
|
))),
|
|
|
|
Err(error) => Err(error),
|
|
|
|
},
|
|
|
|
// Propagate errors by explicitly matching them before the final case.
|
|
|
|
Value::Error { error } => Err(error),
|
|
|
|
other => Err(ShellError::OnlySupportsThisInputType(
|
|
|
|
"list, binary, raw data or range".into(),
|
|
|
|
other.get_type().to_string(),
|
|
|
|
span,
|
|
|
|
// This line requires the Value::Error match above.
|
|
|
|
other.expect_span(),
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
PipelineData::Empty => Err(ShellError::OnlySupportsThisInputType(
|
|
|
|
"list, binary, raw data or range".into(),
|
|
|
|
"null".into(),
|
|
|
|
span,
|
|
|
|
span, // TODO: make PipelineData::Empty spanned, so that the span can be used here.
|
|
|
|
)),
|
|
|
|
other => Ok(PipelineIterator(other)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-27 18:49:03 +01:00
|
|
|
pub fn into_interruptible_iter(self, ctrlc: Option<Arc<AtomicBool>>) -> PipelineIterator {
|
|
|
|
let mut iter = self.into_iter();
|
|
|
|
|
2021-12-24 08:22:11 +01:00
|
|
|
if let PipelineIterator(PipelineData::ListStream(s, ..)) = &mut iter {
|
2021-11-27 18:49:03 +01:00
|
|
|
s.ctrlc = ctrlc;
|
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
|
|
|
}
|
|
|
|
|
2021-12-24 08:22:11 +01:00
|
|
|
pub fn collect_string(self, separator: &str, config: &Config) -> Result<String, ShellError> {
|
2021-10-25 06:24:10 +02:00
|
|
|
match self {
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::Empty => Ok(String::new()),
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::Value(v, ..) => Ok(v.into_string(separator, config)),
|
|
|
|
PipelineData::ListStream(s, ..) => Ok(s.into_string(separator, config)),
|
2022-03-08 02:17:33 +01:00
|
|
|
PipelineData::ExternalStream { stdout: None, .. } => Ok(String::new()),
|
|
|
|
PipelineData::ExternalStream {
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
stdout: Some(s),
|
|
|
|
trim_end_newline,
|
|
|
|
..
|
2022-03-08 02:17:33 +01:00
|
|
|
} => {
|
2022-10-20 12:22:07 +02:00
|
|
|
let mut output = String::new();
|
2022-01-28 19:32:33 +01:00
|
|
|
|
|
|
|
for val in s {
|
2023-01-24 12:23:42 +01:00
|
|
|
output.push_str(&val?.as_string()?);
|
2022-01-28 19:32:33 +01:00
|
|
|
}
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
if trim_end_newline {
|
2023-01-08 22:51:51 +01:00
|
|
|
output.truncate(output.trim_end_matches(LINE_ENDING_PATTERN).len());
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
}
|
2022-01-28 19:32:33 +01:00
|
|
|
Ok(output)
|
2021-12-24 08:22:11 +01:00
|
|
|
}
|
2021-10-25 06:24:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 12:43:46 +01:00
|
|
|
/// Retrieves string from pipeline data.
|
2022-11-21 02:06:09 +01:00
|
|
|
///
|
|
|
|
/// As opposed to `collect_string` this raises error rather than converting non-string values.
|
|
|
|
/// The `span` will be used if `ListStream` is encountered since it doesn't carry a span.
|
|
|
|
pub fn collect_string_strict(
|
|
|
|
self,
|
|
|
|
span: Span,
|
2023-02-11 22:35:48 +01:00
|
|
|
) -> Result<(String, Span, Option<Box<PipelineMetadata>>), ShellError> {
|
2022-11-21 02:06:09 +01:00
|
|
|
match self {
|
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 07:48:53 +01:00
|
|
|
PipelineData::Empty => Ok((String::new(), span, None)),
|
|
|
|
PipelineData::Value(Value::String { val, span }, metadata) => Ok((val, span, metadata)),
|
2022-11-21 02:06:09 +01:00
|
|
|
PipelineData::Value(val, _) => {
|
|
|
|
Err(ShellError::TypeMismatch("string".into(), val.span()?))
|
|
|
|
}
|
|
|
|
PipelineData::ListStream(_, _) => Err(ShellError::TypeMismatch("string".into(), span)),
|
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: None,
|
|
|
|
metadata,
|
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 07:48:53 +01:00
|
|
|
span,
|
2022-11-21 02:06:09 +01:00
|
|
|
..
|
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 07:48:53 +01:00
|
|
|
} => Ok((String::new(), span, metadata)),
|
2022-11-21 02:06:09 +01:00
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: Some(stdout),
|
|
|
|
metadata,
|
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 07:48:53 +01:00
|
|
|
span,
|
2022-11-21 02:06:09 +01:00
|
|
|
..
|
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 07:48:53 +01:00
|
|
|
} => Ok((stdout.into_string()?.item, span, metadata)),
|
2022-11-21 02:06:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-19 08:46:13 +01:00
|
|
|
pub fn follow_cell_path(
|
|
|
|
self,
|
|
|
|
cell_path: &[PathMember],
|
|
|
|
head: Span,
|
2022-06-01 15:34:42 +02:00
|
|
|
insensitive: bool,
|
2023-01-02 23:45:43 +01:00
|
|
|
ignore_errors: bool,
|
2021-12-19 08:46:13 +01:00
|
|
|
) -> Result<Value, ShellError> {
|
2021-10-25 06:24:10 +02:00
|
|
|
match self {
|
|
|
|
// FIXME: there are probably better ways of doing this
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::ListStream(stream, ..) => Value::List {
|
2022-09-01 01:09:40 +02:00
|
|
|
vals: stream.collect(),
|
2021-12-19 08:46:13 +01:00
|
|
|
span: head,
|
2021-10-25 06:24:10 +02:00
|
|
|
}
|
2023-01-02 23:45:43 +01:00
|
|
|
.follow_cell_path(cell_path, insensitive, ignore_errors),
|
|
|
|
PipelineData::Value(v, ..) => v.follow_cell_path(cell_path, insensitive, ignore_errors),
|
2021-12-24 08:22:11 +01:00
|
|
|
_ => Err(ShellError::IOError("can't follow stream paths".into())),
|
2021-10-25 06:24:10 +02:00
|
|
|
}
|
|
|
|
}
|
2021-10-25 23:14:21 +02:00
|
|
|
|
2022-03-17 18:55:02 +01:00
|
|
|
pub fn upsert_cell_path(
|
2021-11-05 04:59:12 +01:00
|
|
|
&mut self,
|
|
|
|
cell_path: &[PathMember],
|
|
|
|
callback: Box<dyn FnOnce(&Value) -> Value>,
|
2021-12-19 08:46:13 +01:00
|
|
|
head: Span,
|
2021-11-05 04:59:12 +01:00
|
|
|
) -> Result<(), ShellError> {
|
|
|
|
match self {
|
|
|
|
// FIXME: there are probably better ways of doing this
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::ListStream(stream, ..) => Value::List {
|
2022-09-01 01:09:40 +02:00
|
|
|
vals: stream.collect(),
|
2021-12-19 08:46:13 +01:00
|
|
|
span: head,
|
2021-11-05 04:59:12 +01:00
|
|
|
}
|
2022-03-17 18:55:02 +01:00
|
|
|
.upsert_cell_path(cell_path, callback),
|
|
|
|
PipelineData::Value(v, ..) => v.upsert_cell_path(cell_path, callback),
|
2021-12-24 08:22:11 +01:00
|
|
|
_ => Ok(()),
|
2021-11-05 04:59:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-25 23:14:21 +02:00
|
|
|
/// Simplified mapper to help with simple values also. For full iterator support use `.into_iter()` instead
|
2021-10-28 06:13:10 +02:00
|
|
|
pub fn map<F>(
|
|
|
|
self,
|
|
|
|
mut f: F,
|
|
|
|
ctrlc: Option<Arc<AtomicBool>>,
|
|
|
|
) -> Result<PipelineData, ShellError>
|
2021-10-25 23:14:21 +02:00
|
|
|
where
|
|
|
|
Self: Sized,
|
|
|
|
F: FnMut(Value) -> Value + 'static + Send,
|
|
|
|
{
|
|
|
|
match self {
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::List { vals, .. }, ..) => {
|
2021-10-28 06:13:10 +02:00
|
|
|
Ok(vals.into_iter().map(f).into_pipeline_data(ctrlc))
|
2021-10-25 23:14:21 +02:00
|
|
|
}
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::Empty => Ok(PipelineData::Empty),
|
2022-09-01 01:09:40 +02:00
|
|
|
PipelineData::ListStream(stream, ..) => Ok(stream.map(f).into_pipeline_data(ctrlc)),
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
|
2022-03-08 02:17:33 +01:00
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: Some(stream),
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
trim_end_newline,
|
2022-03-08 02:17:33 +01:00
|
|
|
..
|
|
|
|
} => {
|
2022-02-07 13:44:18 +01:00
|
|
|
let collected = stream.into_bytes()?;
|
|
|
|
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
if let Ok(mut st) = String::from_utf8(collected.clone().item) {
|
|
|
|
if trim_end_newline {
|
2023-01-08 22:51:51 +01:00
|
|
|
st.truncate(st.trim_end_matches(LINE_ENDING_PATTERN).len());
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
}
|
2022-02-07 13:44:18 +01:00
|
|
|
Ok(f(Value::String {
|
|
|
|
val: st,
|
|
|
|
span: collected.span,
|
|
|
|
})
|
|
|
|
.into_pipeline_data())
|
|
|
|
} else {
|
|
|
|
Ok(f(Value::Binary {
|
|
|
|
val: collected.item,
|
|
|
|
span: collected.span,
|
|
|
|
})
|
|
|
|
.into_pipeline_data())
|
|
|
|
}
|
|
|
|
}
|
2021-12-24 08:22:11 +01:00
|
|
|
|
2022-03-28 08:13:43 +02:00
|
|
|
PipelineData::Value(Value::Range { val, .. }, ..) => Ok(val
|
|
|
|
.into_range_iter(ctrlc.clone())?
|
|
|
|
.map(f)
|
|
|
|
.into_pipeline_data(ctrlc)),
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(v, ..) => match f(v) {
|
2021-11-27 18:49:03 +01:00
|
|
|
Value::Error { error } => Err(error),
|
|
|
|
v => Ok(v.into_pipeline_data()),
|
|
|
|
},
|
2021-10-25 23:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Simplified flatmapper. For full iterator support use `.into_iter()` instead
|
2022-02-24 20:02:28 +01:00
|
|
|
pub fn flat_map<U: 'static, F>(
|
2021-10-28 06:13:10 +02:00
|
|
|
self,
|
|
|
|
mut f: F,
|
|
|
|
ctrlc: Option<Arc<AtomicBool>>,
|
|
|
|
) -> Result<PipelineData, ShellError>
|
2021-10-25 23:14:21 +02:00
|
|
|
where
|
|
|
|
Self: Sized,
|
|
|
|
U: IntoIterator<Item = Value>,
|
|
|
|
<U as IntoIterator>::IntoIter: 'static + Send,
|
|
|
|
F: FnMut(Value) -> U + 'static + Send,
|
|
|
|
{
|
|
|
|
match self {
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::Empty => Ok(PipelineData::Empty),
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::List { vals, .. }, ..) => {
|
2022-02-24 20:02:28 +01:00
|
|
|
Ok(vals.into_iter().flat_map(f).into_pipeline_data(ctrlc))
|
2021-10-25 23:14:21 +02:00
|
|
|
}
|
2022-09-01 01:09:40 +02:00
|
|
|
PipelineData::ListStream(stream, ..) => {
|
|
|
|
Ok(stream.flat_map(f).into_pipeline_data(ctrlc))
|
|
|
|
}
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::Empty),
|
2022-03-08 02:17:33 +01:00
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: Some(stream),
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
trim_end_newline,
|
2022-03-08 02:17:33 +01:00
|
|
|
..
|
|
|
|
} => {
|
2022-02-07 13:44:18 +01:00
|
|
|
let collected = stream.into_bytes()?;
|
|
|
|
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
if let Ok(mut st) = String::from_utf8(collected.clone().item) {
|
|
|
|
if trim_end_newline {
|
2023-01-08 22:51:51 +01:00
|
|
|
st.truncate(st.trim_end_matches(LINE_ENDING_PATTERN).len())
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
}
|
2022-02-07 13:44:18 +01:00
|
|
|
Ok(f(Value::String {
|
|
|
|
val: st,
|
|
|
|
span: collected.span,
|
|
|
|
})
|
|
|
|
.into_iter()
|
|
|
|
.into_pipeline_data(ctrlc))
|
|
|
|
} else {
|
|
|
|
Ok(f(Value::Binary {
|
|
|
|
val: collected.item,
|
|
|
|
span: collected.span,
|
|
|
|
})
|
|
|
|
.into_iter()
|
|
|
|
.into_pipeline_data(ctrlc))
|
|
|
|
}
|
|
|
|
}
|
2023-01-24 12:23:42 +01:00
|
|
|
PipelineData::Value(Value::Range { val, .. }, ..) => Ok(val
|
|
|
|
.into_range_iter(ctrlc.clone())?
|
|
|
|
.flat_map(f)
|
|
|
|
.into_pipeline_data(ctrlc)),
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(v, ..) => Ok(f(v).into_iter().into_pipeline_data(ctrlc)),
|
2021-10-25 23:14:21 +02:00
|
|
|
}
|
|
|
|
}
|
2021-11-07 03:40:44 +01:00
|
|
|
|
|
|
|
pub fn filter<F>(
|
|
|
|
self,
|
|
|
|
mut f: F,
|
|
|
|
ctrlc: Option<Arc<AtomicBool>>,
|
|
|
|
) -> Result<PipelineData, ShellError>
|
|
|
|
where
|
|
|
|
Self: Sized,
|
|
|
|
F: FnMut(&Value) -> bool + 'static + Send,
|
|
|
|
{
|
|
|
|
match self {
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::Empty => Ok(PipelineData::Empty),
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::List { vals, .. }, ..) => {
|
2021-11-07 03:40:44 +01:00
|
|
|
Ok(vals.into_iter().filter(f).into_pipeline_data(ctrlc))
|
|
|
|
}
|
2022-09-01 01:09:40 +02:00
|
|
|
PipelineData::ListStream(stream, ..) => Ok(stream.filter(f).into_pipeline_data(ctrlc)),
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::Empty),
|
2022-03-08 02:17:33 +01:00
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: Some(stream),
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
trim_end_newline,
|
2022-03-08 02:17:33 +01:00
|
|
|
..
|
|
|
|
} => {
|
2022-02-07 13:44:18 +01:00
|
|
|
let collected = stream.into_bytes()?;
|
|
|
|
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
if let Ok(mut st) = String::from_utf8(collected.clone().item) {
|
|
|
|
if trim_end_newline {
|
2023-01-08 22:51:51 +01:00
|
|
|
st.truncate(st.trim_end_matches(LINE_ENDING_PATTERN).len())
|
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description
As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.
And if the command is executed directly like: `cat tmp`, the result
won't change.
Fixes: #6816
Fixes: #3980
Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.
If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.
# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">
After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 04:51:57 +01:00
|
|
|
}
|
2022-02-07 13:44:18 +01:00
|
|
|
let v = Value::String {
|
|
|
|
val: st,
|
|
|
|
span: collected.span,
|
|
|
|
};
|
|
|
|
|
|
|
|
if f(&v) {
|
|
|
|
Ok(v.into_pipeline_data())
|
|
|
|
} else {
|
2022-12-07 19:31:57 +01:00
|
|
|
Ok(PipelineData::new_with_metadata(None, collected.span))
|
2022-02-07 13:44:18 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let v = Value::Binary {
|
|
|
|
val: collected.item,
|
|
|
|
span: collected.span,
|
|
|
|
};
|
|
|
|
|
|
|
|
if f(&v) {
|
|
|
|
Ok(v.into_pipeline_data())
|
|
|
|
} else {
|
2022-12-07 19:31:57 +01:00
|
|
|
Ok(PipelineData::new_with_metadata(None, collected.span))
|
2022-02-07 13:44:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-28 08:13:43 +02:00
|
|
|
PipelineData::Value(Value::Range { val, .. }, ..) => Ok(val
|
|
|
|
.into_range_iter(ctrlc.clone())?
|
|
|
|
.filter(f)
|
|
|
|
.into_pipeline_data(ctrlc)),
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(v, ..) => {
|
2021-11-07 03:40:44 +01:00
|
|
|
if f(&v) {
|
|
|
|
Ok(v.into_pipeline_data())
|
|
|
|
} else {
|
|
|
|
Ok(Value::Nothing { span: v.span()? }.into_pipeline_data())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-26 01:44:57 +02:00
|
|
|
|
2022-12-14 19:25:32 +01:00
|
|
|
/// Try to catch external stream exit status and detect if it runs to failed.
|
|
|
|
///
|
|
|
|
/// This is useful to commands with semicolon, we can detect errors early to avoid
|
|
|
|
/// commands after semicolon running.
|
|
|
|
///
|
|
|
|
/// Returns self and a flag indicates if the external stream runs to failed.
|
|
|
|
/// If `self` is not Pipeline::ExternalStream, the flag will be false.
|
|
|
|
pub fn is_external_failed(self) -> (Self, bool) {
|
|
|
|
let mut failed_to_run = false;
|
|
|
|
// Only need ExternalStream without redirecting output.
|
|
|
|
// It indicates we have no more commands to execute currently.
|
|
|
|
if let PipelineData::ExternalStream {
|
|
|
|
stdout: None,
|
|
|
|
stderr,
|
|
|
|
mut exit_code,
|
|
|
|
span,
|
|
|
|
metadata,
|
|
|
|
trim_end_newline,
|
|
|
|
} = self
|
|
|
|
{
|
|
|
|
let exit_code = exit_code.take();
|
|
|
|
|
|
|
|
// Note:
|
|
|
|
// In run-external's implementation detail, the result sender thread
|
|
|
|
// send out stderr message first, then stdout message, then exit_code.
|
|
|
|
//
|
|
|
|
// In this clause, we already make sure that `stdout` is None
|
|
|
|
// But not the case of `stderr`, so if `stderr` is not None
|
|
|
|
// We need to consume stderr message before reading external commands' exit code.
|
|
|
|
//
|
|
|
|
// Or we'll never have a chance to read exit_code if stderr producer produce too much stderr message.
|
|
|
|
// So we consume stderr stream and rebuild it.
|
|
|
|
let stderr = stderr.map(|stderr_stream| {
|
|
|
|
let stderr_ctrlc = stderr_stream.ctrlc.clone();
|
|
|
|
let stderr_span = stderr_stream.span;
|
2023-01-24 12:23:42 +01:00
|
|
|
let stderr_bytes = stderr_stream
|
|
|
|
.into_bytes()
|
|
|
|
.map(|bytes| bytes.item)
|
|
|
|
.unwrap_or_default();
|
2022-12-14 19:25:32 +01:00
|
|
|
RawStream::new(
|
|
|
|
Box::new(vec![Ok(stderr_bytes)].into_iter()),
|
|
|
|
stderr_ctrlc,
|
|
|
|
stderr_span,
|
2023-01-11 02:57:48 +01:00
|
|
|
None,
|
2022-12-14 19:25:32 +01:00
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
match exit_code {
|
|
|
|
Some(exit_code_stream) => {
|
|
|
|
let ctrlc = exit_code_stream.ctrlc.clone();
|
|
|
|
let exit_code: Vec<Value> = exit_code_stream.into_iter().collect();
|
|
|
|
if let Some(Value::Int { val: code, .. }) = exit_code.last() {
|
Fix typos by codespell (#7600)
# Description
Found via `codespell -S target -L
crate,ser,numer,falsy,ro,te,nd,bu,ndoes,statics,ons,fo,rouge,pard`
# User-Facing Changes
None.
# Tests + Formatting
None and done.
# After Submitting
None.
2022-12-26 08:31:26 +01:00
|
|
|
// if exit_code is not 0, it indicates error occurred, return back Err.
|
2022-12-14 19:25:32 +01:00
|
|
|
if *code != 0 {
|
|
|
|
failed_to_run = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(
|
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: None,
|
|
|
|
stderr,
|
|
|
|
exit_code: Some(ListStream::from_stream(exit_code.into_iter(), ctrlc)),
|
|
|
|
span,
|
|
|
|
metadata,
|
|
|
|
trim_end_newline,
|
|
|
|
},
|
|
|
|
failed_to_run,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
None => (
|
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: None,
|
|
|
|
stderr,
|
|
|
|
exit_code: None,
|
|
|
|
span,
|
|
|
|
metadata,
|
|
|
|
trim_end_newline,
|
|
|
|
},
|
|
|
|
failed_to_run,
|
|
|
|
),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
(self, false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-02 16:54:49 +02:00
|
|
|
/// Consume and print self data immediately.
|
|
|
|
///
|
|
|
|
/// `no_newline` controls if we need to attach newline character to output.
|
Fix typos by codespell (#7600)
# Description
Found via `codespell -S target -L
crate,ser,numer,falsy,ro,te,nd,bu,ndoes,statics,ons,fo,rouge,pard`
# User-Facing Changes
None.
# Tests + Formatting
None and done.
# After Submitting
None.
2022-12-26 08:31:26 +01:00
|
|
|
/// `to_stderr` controls if data is output to stderr, when the value is false, the data is output to stdout.
|
2022-05-06 22:33:00 +02:00
|
|
|
pub fn print(
|
|
|
|
self,
|
|
|
|
engine_state: &EngineState,
|
|
|
|
stack: &mut Stack,
|
|
|
|
no_newline: bool,
|
2022-07-02 16:54:49 +02:00
|
|
|
to_stderr: bool,
|
2022-10-10 14:32:55 +02:00
|
|
|
) -> Result<i64, ShellError> {
|
2022-04-26 01:44:57 +02:00
|
|
|
// If the table function is in the declarations, then we can use it
|
|
|
|
// to create the table value that will be printed in the terminal
|
|
|
|
|
|
|
|
let config = engine_state.get_config();
|
|
|
|
|
|
|
|
if let PipelineData::ExternalStream {
|
|
|
|
stdout: stream,
|
2022-10-12 15:41:20 +02:00
|
|
|
stderr: stderr_stream,
|
2022-04-26 01:44:57 +02:00
|
|
|
exit_code,
|
|
|
|
..
|
|
|
|
} = self
|
|
|
|
{
|
2022-11-06 01:46:40 +01:00
|
|
|
return print_if_stream(stream, stderr_stream, to_stderr, exit_code);
|
2022-04-26 01:44:57 +02:00
|
|
|
}
|
|
|
|
|
2023-01-24 12:23:42 +01:00
|
|
|
if let Some(decl_id) = engine_state.find_decl("table".as_bytes(), &[]) {
|
|
|
|
let command = engine_state.get_decl(decl_id);
|
|
|
|
if command.get_block_id().is_some() {
|
|
|
|
return self.write_all_and_flush(engine_state, config, no_newline, to_stderr);
|
|
|
|
}
|
2022-07-26 01:41:30 +02:00
|
|
|
|
2023-01-24 12:23:42 +01:00
|
|
|
let table = command.run(engine_state, stack, &Call::new(Span::new(0, 0)), self)?;
|
2022-04-26 01:44:57 +02:00
|
|
|
|
2023-01-24 12:23:42 +01:00
|
|
|
table.write_all_and_flush(engine_state, config, no_newline, to_stderr)?;
|
|
|
|
} else {
|
|
|
|
self.write_all_and_flush(engine_state, config, no_newline, to_stderr)?;
|
2022-07-25 13:38:21 +02:00
|
|
|
};
|
2022-05-01 22:40:46 +02:00
|
|
|
|
2022-10-10 14:32:55 +02:00
|
|
|
Ok(0)
|
2022-07-25 13:38:21 +02:00
|
|
|
}
|
2022-05-06 22:33:00 +02:00
|
|
|
|
2023-02-09 19:29:34 +01:00
|
|
|
/// Consume and print self data immediately.
|
|
|
|
///
|
|
|
|
/// Unlike [print] does not call `table` to format data and just prints it
|
|
|
|
/// one element on a line
|
|
|
|
/// * `no_newline` controls if we need to attach newline character to output.
|
|
|
|
/// * `to_stderr` controls if data is output to stderr, when the value is false, the data is output to stdout.
|
|
|
|
pub fn print_not_formatted(
|
|
|
|
self,
|
|
|
|
engine_state: &EngineState,
|
|
|
|
no_newline: bool,
|
|
|
|
to_stderr: bool,
|
|
|
|
) -> Result<i64, ShellError> {
|
|
|
|
let config = engine_state.get_config();
|
|
|
|
|
|
|
|
if let PipelineData::ExternalStream {
|
|
|
|
stdout: stream,
|
|
|
|
stderr: stderr_stream,
|
|
|
|
exit_code,
|
|
|
|
..
|
|
|
|
} = self
|
|
|
|
{
|
|
|
|
print_if_stream(stream, stderr_stream, to_stderr, exit_code)
|
|
|
|
} else {
|
|
|
|
self.write_all_and_flush(engine_state, config, no_newline, to_stderr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-25 13:38:21 +02:00
|
|
|
fn write_all_and_flush(
|
|
|
|
self,
|
|
|
|
engine_state: &EngineState,
|
|
|
|
config: &Config,
|
|
|
|
no_newline: bool,
|
|
|
|
to_stderr: bool,
|
2022-10-10 14:32:55 +02:00
|
|
|
) -> Result<i64, ShellError> {
|
2022-07-25 13:38:21 +02:00
|
|
|
for item in self {
|
2023-01-02 23:45:43 +01:00
|
|
|
let mut is_err = false;
|
2022-07-25 13:38:21 +02:00
|
|
|
let mut out = if let Value::Error { error } = item {
|
|
|
|
let working_set = StateWorkingSet::new(engine_state);
|
2023-01-02 23:45:43 +01:00
|
|
|
// Value::Errors must always go to stderr, not stdout.
|
|
|
|
is_err = true;
|
2022-07-25 13:38:21 +02:00
|
|
|
format_error(&working_set, &error)
|
|
|
|
} else if no_newline {
|
|
|
|
item.into_string("", config)
|
|
|
|
} else {
|
|
|
|
item.into_string("\n", config)
|
|
|
|
};
|
|
|
|
|
|
|
|
if !no_newline {
|
|
|
|
out.push('\n');
|
|
|
|
}
|
2022-04-26 01:44:57 +02:00
|
|
|
|
2023-01-02 23:45:43 +01:00
|
|
|
if !to_stderr && !is_err {
|
2022-07-25 13:38:21 +02:00
|
|
|
stdout_write_all_and_flush(out)?
|
|
|
|
} else {
|
|
|
|
stderr_write_all_and_flush(out)?
|
2022-04-26 01:44:57 +02:00
|
|
|
}
|
2022-07-25 13:38:21 +02:00
|
|
|
}
|
2022-04-26 01:44:57 +02:00
|
|
|
|
2022-10-10 14:32:55 +02:00
|
|
|
Ok(0)
|
2022-04-26 01:44:57 +02:00
|
|
|
}
|
2021-10-25 06:01:02 +02:00
|
|
|
}
|
|
|
|
|
2021-10-25 23:14:21 +02:00
|
|
|
pub struct PipelineIterator(PipelineData);
|
|
|
|
|
|
|
|
impl IntoIterator for PipelineData {
|
2021-10-25 06:01:02 +02:00
|
|
|
type Item = Value;
|
|
|
|
|
2021-10-25 23:14:21 +02:00
|
|
|
type IntoIter = PipelineIterator;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
2021-10-25 06:01:02 +02:00
|
|
|
match self {
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::List { vals, .. }, metadata) => {
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineIterator(PipelineData::ListStream(
|
2022-01-28 19:32:33 +01:00
|
|
|
ListStream {
|
2022-09-01 01:09:40 +02:00
|
|
|
stream: Box::new(vals.into_iter()),
|
2021-12-02 06:59:10 +01:00
|
|
|
ctrlc: None,
|
|
|
|
},
|
|
|
|
metadata,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
PipelineData::Value(Value::Range { val, .. }, metadata) => {
|
2022-03-28 08:13:43 +02:00
|
|
|
match val.into_range_iter(None) {
|
2021-12-24 08:22:11 +01:00
|
|
|
Ok(iter) => PipelineIterator(PipelineData::ListStream(
|
2022-01-28 19:32:33 +01:00
|
|
|
ListStream {
|
2022-09-01 01:09:40 +02:00
|
|
|
stream: Box::new(iter),
|
2021-12-02 06:59:10 +01:00
|
|
|
ctrlc: None,
|
|
|
|
},
|
|
|
|
metadata,
|
|
|
|
)),
|
2021-12-24 08:22:11 +01:00
|
|
|
Err(error) => PipelineIterator(PipelineData::ListStream(
|
2022-01-28 19:32:33 +01:00
|
|
|
ListStream {
|
2022-09-01 01:09:40 +02:00
|
|
|
stream: Box::new(std::iter::once(Value::Error { error })),
|
2021-12-02 06:59:10 +01:00
|
|
|
ctrlc: None,
|
|
|
|
},
|
|
|
|
metadata,
|
|
|
|
)),
|
|
|
|
}
|
2021-10-28 06:13:10 +02:00
|
|
|
}
|
2021-10-25 23:14:21 +02:00
|
|
|
x => PipelineIterator(x),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-06 01:46:40 +01:00
|
|
|
pub fn print_if_stream(
|
|
|
|
stream: Option<RawStream>,
|
|
|
|
stderr_stream: Option<RawStream>,
|
|
|
|
to_stderr: bool,
|
|
|
|
exit_code: Option<ListStream>,
|
|
|
|
) -> Result<i64, ShellError> {
|
|
|
|
// NOTE: currently we don't need anything from stderr
|
2023-01-28 21:40:52 +01:00
|
|
|
// so we just consume and throw away `stderr_stream` to make sure the pipe doesn't fill up
|
|
|
|
thread::Builder::new()
|
|
|
|
.name("stderr consumer".to_string())
|
|
|
|
.spawn(move || stderr_stream.map(|x| x.into_bytes()))
|
|
|
|
.expect("could not create thread");
|
2022-11-06 01:46:40 +01:00
|
|
|
if let Some(stream) = stream {
|
|
|
|
for s in stream {
|
|
|
|
let s_live = s?;
|
|
|
|
let bin_output = s_live.as_binary()?;
|
|
|
|
|
|
|
|
if !to_stderr {
|
|
|
|
stdout_write_all_and_flush(bin_output)?
|
|
|
|
} else {
|
|
|
|
stderr_write_all_and_flush(bin_output)?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure everything has finished
|
|
|
|
if let Some(exit_code) = exit_code {
|
|
|
|
let mut exit_codes: Vec<_> = exit_code.into_iter().collect();
|
|
|
|
return match exit_codes.pop() {
|
|
|
|
#[cfg(unix)]
|
|
|
|
Some(Value::Error { error }) => Err(error),
|
|
|
|
Some(Value::Int { val, .. }) => Ok(val),
|
|
|
|
_ => Ok(0),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(0)
|
|
|
|
}
|
|
|
|
|
2021-10-25 23:14:21 +02:00
|
|
|
impl Iterator for PipelineIterator {
|
|
|
|
type Item = Value;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
match &mut self.0 {
|
2022-12-07 19:31:57 +01:00
|
|
|
PipelineData::Empty => None,
|
2021-12-02 06:59:10 +01:00
|
|
|
PipelineData::Value(Value::Nothing { .. }, ..) => None,
|
|
|
|
PipelineData::Value(v, ..) => Some(std::mem::take(v)),
|
2022-09-01 01:09:40 +02:00
|
|
|
PipelineData::ListStream(stream, ..) => stream.next(),
|
2022-03-08 02:17:33 +01:00
|
|
|
PipelineData::ExternalStream { stdout: None, .. } => None,
|
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: Some(stream),
|
|
|
|
..
|
|
|
|
} => stream.next().map(|x| match x {
|
2022-01-28 19:32:33 +01:00
|
|
|
Ok(x) => x,
|
2021-12-24 20:24:55 +01:00
|
|
|
Err(err) => Value::Error { error: err },
|
2021-12-24 08:22:11 +01:00
|
|
|
}),
|
2021-10-25 06:01:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait IntoPipelineData {
|
|
|
|
fn into_pipeline_data(self) -> PipelineData;
|
2023-02-11 22:35:48 +01:00
|
|
|
|
2022-11-21 02:06:09 +01:00
|
|
|
fn into_pipeline_data_with_metadata(
|
|
|
|
self,
|
2023-02-11 22:35:48 +01:00
|
|
|
metadata: impl Into<Option<Box<PipelineMetadata>>>,
|
2022-11-21 02:06:09 +01:00
|
|
|
) -> PipelineData;
|
2021-10-25 06:01:02 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 18:49:03 +01:00
|
|
|
impl<V> IntoPipelineData for V
|
|
|
|
where
|
2022-09-01 01:09:40 +02:00
|
|
|
V: Into<Value>,
|
2021-11-27 18:49:03 +01:00
|
|
|
{
|
2021-10-25 06:01:02 +02:00
|
|
|
fn into_pipeline_data(self) -> PipelineData {
|
2022-09-01 01:09:40 +02:00
|
|
|
PipelineData::Value(self.into(), None)
|
2021-10-25 06:01:02 +02:00
|
|
|
}
|
2023-02-11 22:35:48 +01:00
|
|
|
|
2022-11-21 02:06:09 +01:00
|
|
|
fn into_pipeline_data_with_metadata(
|
|
|
|
self,
|
2023-02-11 22:35:48 +01:00
|
|
|
metadata: impl Into<Option<Box<PipelineMetadata>>>,
|
2022-11-21 02:06:09 +01:00
|
|
|
) -> PipelineData {
|
|
|
|
PipelineData::Value(self.into(), metadata.into())
|
2022-11-15 18:12:56 +01:00
|
|
|
}
|
2021-10-25 06:01:02 +02:00
|
|
|
}
|
|
|
|
|
2021-10-28 06:13:10 +02:00
|
|
|
pub trait IntoInterruptiblePipelineData {
|
|
|
|
fn into_pipeline_data(self, ctrlc: Option<Arc<AtomicBool>>) -> PipelineData;
|
2021-12-02 06:59:10 +01:00
|
|
|
fn into_pipeline_data_with_metadata(
|
|
|
|
self,
|
2023-02-11 22:35:48 +01:00
|
|
|
metadata: impl Into<Option<Box<PipelineMetadata>>>,
|
2021-12-02 06:59:10 +01:00
|
|
|
ctrlc: Option<Arc<AtomicBool>>,
|
|
|
|
) -> PipelineData;
|
2021-10-28 06:13:10 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 18:49:03 +01:00
|
|
|
impl<I> IntoInterruptiblePipelineData for I
|
2021-10-25 06:01:02 +02:00
|
|
|
where
|
2021-11-27 18:49:03 +01:00
|
|
|
I: IntoIterator + Send + 'static,
|
|
|
|
I::IntoIter: Send + 'static,
|
2022-09-01 01:09:40 +02:00
|
|
|
<I::IntoIter as Iterator>::Item: Into<Value>,
|
2021-10-25 06:01:02 +02:00
|
|
|
{
|
2021-10-28 06:13:10 +02:00
|
|
|
fn into_pipeline_data(self, ctrlc: Option<Arc<AtomicBool>>) -> PipelineData {
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::ListStream(
|
2022-01-28 19:32:33 +01:00
|
|
|
ListStream {
|
2021-12-02 06:59:10 +01:00
|
|
|
stream: Box::new(self.into_iter().map(Into::into)),
|
|
|
|
ctrlc,
|
|
|
|
},
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn into_pipeline_data_with_metadata(
|
|
|
|
self,
|
2023-02-11 22:35:48 +01:00
|
|
|
metadata: impl Into<Option<Box<PipelineMetadata>>>,
|
2021-12-02 06:59:10 +01:00
|
|
|
ctrlc: Option<Arc<AtomicBool>>,
|
|
|
|
) -> PipelineData {
|
2021-12-24 08:22:11 +01:00
|
|
|
PipelineData::ListStream(
|
2022-01-28 19:32:33 +01:00
|
|
|
ListStream {
|
2021-12-02 06:59:10 +01:00
|
|
|
stream: Box::new(self.into_iter().map(Into::into)),
|
|
|
|
ctrlc,
|
|
|
|
},
|
2022-11-21 02:06:09 +01:00
|
|
|
metadata.into(),
|
2021-12-02 06:59:10 +01:00
|
|
|
)
|
2021-10-25 06:01:02 +02:00
|
|
|
}
|
|
|
|
}
|