Introduce metadata into the pipeline (#397)

This commit is contained in:
JT 2021-12-02 18:59:10 +13:00 committed by GitHub
parent 56307553ae
commit 45eba8b922
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 329 additions and 199 deletions

View File

@ -34,19 +34,22 @@ impl Command for Echo {
let n = to_be_echoed.len();
match n.cmp(&1usize) {
// More than one value is converted in a stream of values
std::cmp::Ordering::Greater => PipelineData::Stream(ValueStream::from_stream(
to_be_echoed.into_iter(),
engine_state.ctrlc.clone(),
)),
std::cmp::Ordering::Greater => PipelineData::Stream(
ValueStream::from_stream(to_be_echoed.into_iter(), engine_state.ctrlc.clone()),
None,
),
// But a single value can be forwarded as it is
std::cmp::Ordering::Equal => PipelineData::Value(to_be_echoed[0].clone()),
std::cmp::Ordering::Equal => PipelineData::Value(to_be_echoed[0].clone(), None),
// When there are no elements, we echo the empty string
std::cmp::Ordering::Less => PipelineData::Value(Value::String {
val: "".to_string(),
span: call.head,
}),
std::cmp::Ordering::Less => PipelineData::Value(
Value::String {
val: "".to_string(),
span: call.head,
},
None,
),
}
})
}

View File

@ -1,10 +1,10 @@
use chrono::{DateTime, Utc};
use lscolors::{LsColors, Style};
use nu_engine::eval_expression;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, IntoInterruptiblePipelineData, PipelineData, Signature, SyntaxShape, Value,
Category, DataSource, IntoInterruptiblePipelineData, PipelineData, PipelineMetadata, Signature,
SyntaxShape, Value,
};
#[derive(Clone)]
@ -37,7 +37,6 @@ impl Command for Ls {
call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let config = stack.get_config()?;
let pattern = if let Some(expr) = call.positional.get(0) {
let result = eval_expression(engine_state, stack, expr)?;
let mut result = result.as_string()?;
@ -57,10 +56,6 @@ impl Command for Ls {
let call_span = call.head;
let glob = glob::glob(&pattern).unwrap();
let ls_colors = match stack.get_env_var("LS_COLORS") {
Some(s) => LsColors::from_string(&s),
None => LsColors::default(),
};
Ok(glob
.into_iter()
@ -72,22 +67,11 @@ impl Command for Ls {
let is_dir = metadata.is_dir();
let filesize = metadata.len();
let mut cols = vec!["name".into(), "type".into(), "size".into()];
let style =
ls_colors.style_for_path_with_metadata(path.clone(), Some(&metadata));
let ansi_style = style.map(Style::to_crossterm_style).unwrap_or_default();
let use_ls_colors = config.use_ls_colors;
let mut vals = vec![
if use_ls_colors {
Value::String {
val: ansi_style.apply(path.to_string_lossy()).to_string(),
span: call_span,
}
} else {
Value::String {
val: path.to_string_lossy().to_string(),
span: call_span,
}
Value::String {
val: path.to_string_lossy().to_string(),
span: call_span,
},
if is_symlink {
Value::string("symlink", call_span)
@ -120,34 +104,26 @@ impl Command for Ls {
span: call_span,
}
}
Err(_) => {
let style = ls_colors.style_for_path(path.clone());
let ansi_style = style.map(Style::to_crossterm_style).unwrap_or_default();
let use_ls_colors = config.use_ls_colors;
Value::Record {
cols: vec!["name".into(), "type".into(), "size".into()],
vals: vec![
if use_ls_colors {
Value::String {
val: ansi_style.apply(path.to_string_lossy()).to_string(),
span: call_span,
}
} else {
Value::String {
val: path.to_string_lossy().to_string(),
span: call_span,
}
},
Value::Nothing { span: call_span },
Value::Nothing { span: call_span },
],
span: call_span,
}
}
Err(_) => Value::Record {
cols: vec!["name".into(), "type".into(), "size".into()],
vals: vec![
Value::String {
val: path.to_string_lossy().to_string(),
span: call_span,
},
Value::Nothing { span: call_span },
Value::Nothing { span: call_span },
],
span: call_span,
},
},
_ => Value::Nothing { span: call_span },
})
.into_pipeline_data(engine_state.ctrlc.clone()))
.into_pipeline_data_with_metadata(
PipelineMetadata {
data_source: DataSource::Ls,
},
engine_state.ctrlc.clone(),
))
}
}

View File

@ -74,8 +74,8 @@ impl Command for Each {
let span = call.head;
match input {
PipelineData::Value(Value::Range { .. })
| PipelineData::Value(Value::List { .. })
PipelineData::Value(Value::Range { .. }, ..)
| PipelineData::Value(Value::List { .. }, ..)
| PipelineData::Stream { .. } => Ok(input
.into_iter()
.enumerate()
@ -109,7 +109,7 @@ impl Command for Each {
}
})
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Record { cols, vals, .. }) => {
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
let mut output_cols = vec![];
let mut output_vals = vec![];
@ -138,9 +138,12 @@ impl Command for Each {
}
match eval_block(&engine_state, &mut stack, block, PipelineData::new(span))? {
PipelineData::Value(Value::Record {
mut cols, mut vals, ..
}) => {
PipelineData::Value(
Value::Record {
mut cols, mut vals, ..
},
..,
) => {
// TODO check that the lengths match when traversing record
output_cols.append(&mut cols);
output_vals.append(&mut vals);
@ -159,7 +162,7 @@ impl Command for Each {
}
.into_pipeline_data())
}
PipelineData::Value(x) => {
PipelineData::Value(x, ..) => {
let block = engine_state.get_block(block_id);
if let Some(var) = block.signature.get_positional(0) {

View File

@ -26,7 +26,7 @@ impl Command for Length {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
match input {
PipelineData::Value(Value::Nothing { .. }) => Ok(Value::Int {
PipelineData::Value(Value::Nothing { .. }, ..) => Ok(Value::Int {
val: 0,
span: call.head,
}

View File

@ -34,7 +34,7 @@ impl Command for Lines {
// Collect is needed because the string may not live long enough for
// the Rc structure to continue using it. If split could take ownership
// of the split values, then this wouldn't be needed
PipelineData::Value(Value::String { val, span }) => {
PipelineData::Value(Value::String { val, span }, ..) => {
let lines = val
.split(SPLIT_CHAR)
.map(|s| s.to_string())
@ -50,7 +50,7 @@ impl Command for Lines {
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
}
PipelineData::Stream(stream) => {
PipelineData::Stream(stream, ..) => {
let iter = stream
.into_iter()
.filter_map(|value| {
@ -78,7 +78,7 @@ impl Command for Lines {
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
}
PipelineData::Value(val) => Err(ShellError::UnsupportedInput(
PipelineData::Value(val, ..) => Err(ShellError::UnsupportedInput(
format!("Not supported input: {}", val.as_string()?),
call.head,
)),

View File

@ -57,7 +57,7 @@ impl Command for ParEach {
let span = call.head;
match input {
PipelineData::Value(Value::Range { val, .. }) => Ok(val
PipelineData::Value(Value::Range { val, .. }, ..) => Ok(val
.into_range_iter()?
.enumerate()
.par_bridge()
@ -98,7 +98,7 @@ impl Command for ParEach {
.into_iter()
.flatten()
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::List { vals: val, .. }) => Ok(val
PipelineData::Value(Value::List { vals: val, .. }, ..) => Ok(val
.into_iter()
.enumerate()
.par_bridge()
@ -139,7 +139,7 @@ impl Command for ParEach {
.into_iter()
.flatten()
.into_pipeline_data(ctrlc)),
PipelineData::Stream(stream) => Ok(stream
PipelineData::Stream(stream, ..) => Ok(stream
.enumerate()
.par_bridge()
.map(move |(idx, x)| {
@ -179,7 +179,7 @@ impl Command for ParEach {
.into_iter()
.flatten()
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Record { cols, vals, .. }) => {
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
let mut output_cols = vec![];
let mut output_vals = vec![];
@ -208,9 +208,12 @@ impl Command for ParEach {
}
match eval_block(&engine_state, &mut stack, block, PipelineData::new(span))? {
PipelineData::Value(Value::Record {
mut cols, mut vals, ..
}) => {
PipelineData::Value(
Value::Record {
mut cols, mut vals, ..
},
..,
) => {
// TODO check that the lengths match when traversing record
output_cols.append(&mut cols);
output_vals.append(&mut vals);
@ -229,7 +232,7 @@ impl Command for ParEach {
}
.into_pipeline_data())
}
PipelineData::Value(x) => {
PipelineData::Value(x, ..) => {
let block = engine_state.get_block(block_id);
if let Some(var) = block.signature.get_positional(0) {

View File

@ -90,7 +90,10 @@ impl Command for Range {
};
if from > to {
Ok(PipelineData::Value(Value::Nothing { span: call.head }))
Ok(PipelineData::Value(
Value::Nothing { span: call.head },
None,
))
} else {
let iter = v.into_iter().skip(from).take(to - from + 1);
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
@ -100,7 +103,10 @@ impl Command for Range {
let to = rows_to as usize;
if from > to {
Ok(PipelineData::Value(Value::Nothing { span: call.head }))
Ok(PipelineData::Value(
Value::Nothing { span: call.head },
None,
))
} else {
let iter = input.into_iter().skip(from).take(to - from + 1);
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))

View File

@ -68,10 +68,13 @@ fn select(
}
match input {
PipelineData::Value(Value::List {
vals: input_vals,
span,
}) => {
PipelineData::Value(
Value::List {
vals: input_vals,
span,
},
..,
) => {
let mut output = vec![];
for input_val in input_vals {
@ -92,7 +95,7 @@ fn select(
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
}
PipelineData::Stream(stream) => Ok(stream
PipelineData::Stream(stream, ..) => Ok(stream
.map(move |x| {
let mut cols = vec![];
let mut vals = vec![];
@ -113,7 +116,7 @@ fn select(
Value::Record { cols, vals, span }
})
.into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Value(v) => {
PipelineData::Value(v, ..) => {
let mut cols = vec![];
let mut vals = vec![];

View File

@ -35,7 +35,7 @@ impl Command for Wrap {
let name: String = call.req(engine_state, stack, 0)?;
match input {
PipelineData::Value(Value::List { vals, .. }) => Ok(vals
PipelineData::Value(Value::List { vals, .. }, ..) => Ok(vals
.into_iter()
.map(move |x| Value::Record {
cols: vec![name.clone()],
@ -43,14 +43,14 @@ impl Command for Wrap {
span,
})
.into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Stream(stream) => Ok(stream
PipelineData::Stream(stream, ..) => Ok(stream
.map(move |x| Value::Record {
cols: vec![name.clone()],
vals: vec![x],
span,
})
.into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Value(input) => Ok(Value::Record {
PipelineData::Value(input, ..) => Ok(Value::Record {
cols: vec![name],
vals: vec![input],
span,

View File

@ -230,10 +230,13 @@ fn from_eml(
);
}
Ok(PipelineData::Value(Value::from(Spanned {
item: collected,
span: head,
})))
Ok(PipelineData::Value(
Value::from(Spanned {
item: collected,
span: head,
}),
None,
))
}
#[cfg(test)]

View File

@ -194,7 +194,7 @@ fn from_ods(
span: head,
};
Ok(PipelineData::Value(record))
Ok(PipelineData::Value(record, None))
}
#[cfg(test)]

View File

@ -67,11 +67,14 @@ fn from_url(input: PipelineData, head: Span, config: &Config) -> Result<Pipeline
vals.push(Value::String { val: v, span: head })
}
Ok(PipelineData::Value(Value::Record {
cols,
vals,
span: head,
}))
Ok(PipelineData::Value(
Value::Record {
cols,
vals,
span: head,
},
None,
))
}
_ => Err(ShellError::UnsupportedInput(
"String not compatible with url-encoding".to_string(),

View File

@ -194,7 +194,7 @@ fn from_xlsx(
span: head,
};
Ok(PipelineData::Value(record))
Ok(PipelineData::Value(record, None))
}
#[cfg(test)]

View File

@ -57,14 +57,14 @@ pub fn eval(
) -> Result<PipelineData, ShellError> {
if let Some(expr) = spanned_expr {
match parse(&expr.item, &expr.span) {
Ok(value) => Ok(PipelineData::Value(value)),
Ok(value) => Ok(PipelineData::Value(value, None)),
Err(err) => Err(ShellError::UnsupportedInput(
format!("Math evaluation error: {}", err),
expr.span,
)),
}
} else {
if let PipelineData::Value(Value::Nothing { .. }) = input {
if let PipelineData::Value(Value::Nothing { .. }, ..) = input {
return Ok(input);
}
input.map(

View File

@ -62,12 +62,12 @@ pub fn calculate(
mf: impl Fn(&[Value], &Span) -> Result<Value, ShellError>,
) -> Result<Value, ShellError> {
match values {
PipelineData::Stream(s) => helper_for_tables(&s.collect::<Vec<Value>>(), name, mf),
PipelineData::Value(Value::List { ref vals, .. }) => match &vals[..] {
PipelineData::Stream(s, ..) => helper_for_tables(&s.collect::<Vec<Value>>(), name, mf),
PipelineData::Value(Value::List { ref vals, .. }, ..) => match &vals[..] {
[Value::Record { .. }, _end @ ..] => helper_for_tables(vals, name, mf),
_ => mf(vals, &name),
},
PipelineData::Value(Value::Record { vals, cols, span }) => {
PipelineData::Value(Value::Record { vals, cols, span }, ..) => {
let new_vals: Result<Vec<Value>, ShellError> =
vals.into_iter().map(|val| mf(&[val], &name)).collect();
match new_vals {
@ -79,7 +79,7 @@ pub fn calculate(
Err(err) => Err(err),
}
}
PipelineData::Value(Value::Range { val, .. }) => {
PipelineData::Value(Value::Range { val, .. }, ..) => {
let new_vals: Result<Vec<Value>, ShellError> = val
.into_range_iter()?
.map(|val| mf(&[val], &name))
@ -87,6 +87,6 @@ pub fn calculate(
mf(&new_vals?, &name)
}
PipelineData::Value(val) => mf(&[val], &name),
PipelineData::Value(val, ..) => mf(&[val], &name),
}
}

View File

@ -78,10 +78,13 @@ fn bool(
let mut rng = thread_rng();
let bool_result: bool = rng.gen_bool(probability);
Ok(PipelineData::Value(Value::Bool {
val: bool_result,
span,
}))
Ok(PipelineData::Value(
Value::Bool {
val: bool_result,
span,
},
None,
))
}
#[cfg(test)]

View File

@ -70,10 +70,13 @@ fn chars(
.map(char::from)
.collect::<String>();
Ok(PipelineData::Value(Value::String {
val: random_string,
span,
}))
Ok(PipelineData::Value(
Value::String {
val: random_string,
span,
},
None,
))
}
#[cfg(test)]

View File

@ -125,7 +125,10 @@ fn format(
// We can only handle a Record or a List of Record's
match data_as_value {
Value::Record { .. } => match format_record(format_operations, &data_as_value) {
Ok(value) => Ok(PipelineData::Value(Value::string(value, Span::unknown()))),
Ok(value) => Ok(PipelineData::Value(
Value::string(value, Span::unknown()),
None,
)),
Err(value) => Err(value),
},
@ -151,10 +154,10 @@ fn format(
}
}
Ok(PipelineData::Stream(ValueStream::from_stream(
list.into_iter(),
Ok(PipelineData::Stream(
ValueStream::from_stream(list.into_iter(), None),
None,
)))
))
}
_ => Err(ShellError::UnsupportedInput(
"Input data is not supported by this command.".to_string(),

View File

@ -74,6 +74,7 @@ fn operate(
let head = call.head;
let pattern: Spanned<String> = call.req(engine_state, stack, 0)?;
let regex: bool = call.has_flag("regex");
let ctrlc = engine_state.ctrlc.clone();
let pattern_item = pattern.item;
let pattern_span = pattern.span;
@ -125,10 +126,10 @@ fn operate(
}
}
Ok(PipelineData::Stream(ValueStream::from_stream(
parsed.into_iter(),
Ok(PipelineData::Stream(
ValueStream::from_stream(parsed.into_iter(), ctrlc),
None,
)))
))
}
fn build_regex(input: &str, span: Span) -> Result<String, ShellError> {

View File

@ -94,7 +94,7 @@ impl ExternalCommand {
// If there is an input from the pipeline. The stdin from the process
// is piped so it can be used to send the input information
if !matches!(input, PipelineData::Value(Value::Nothing { .. })) {
if !matches!(input, PipelineData::Value(Value::Nothing { .. }, ..)) {
process.stdin(Stdio::piped());
}

View File

@ -64,7 +64,7 @@ prints out the list properly."#
let use_grid_icons = config.use_grid_icons;
match input {
PipelineData::Value(Value::List { vals, .. }) => {
PipelineData::Value(Value::List { vals, .. }, ..) => {
// dbg!("value::list");
let data = convert_to_list(vals, &config);
if let Some(items) = data {
@ -81,7 +81,7 @@ prints out the list properly."#
Ok(PipelineData::new(call.head))
}
}
PipelineData::Stream(stream) => {
PipelineData::Stream(stream, ..) => {
// dbg!("value::stream");
let data = convert_to_list(stream, &config);
if let Some(items) = data {
@ -99,7 +99,7 @@ prints out the list properly."#
Ok(PipelineData::new(call.head))
}
}
PipelineData::Value(Value::Record { cols, vals, .. }) => {
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
// dbg!("value::record");
let mut items = vec![];

View File

@ -1,9 +1,11 @@
use super::color_config::style_primitive;
use crate::viewers::color_config::get_color_config;
use lscolors::{LsColors, Style};
use nu_protocol::ast::{Call, PathMember};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Config, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value,
Category, Config, DataSource, IntoPipelineData, PipelineData, PipelineMetadata, ShellError,
Signature, Span, Value, ValueStream,
};
use nu_table::{StyledString, TextStyle, Theme};
use std::sync::atomic::{AtomicBool, Ordering};
@ -45,7 +47,7 @@ impl Command for Table {
};
match input {
PipelineData::Value(Value::List { vals, .. }) => {
PipelineData::Value(Value::List { vals, .. }, ..) => {
let table = convert_to_table(vals, ctrlc, &config)?;
if let Some(table) = table {
@ -60,7 +62,84 @@ impl Command for Table {
Ok(PipelineData::new(call.head))
}
}
PipelineData::Stream(stream) => {
PipelineData::Stream(stream, metadata) => {
let stream = match metadata {
Some(PipelineMetadata {
data_source: DataSource::Ls,
}) => {
let config = config.clone();
let ctrlc = ctrlc.clone();
let ls_colors = match stack.get_env_var("LS_COLORS") {
Some(s) => LsColors::from_string(&s),
None => LsColors::default(),
};
ValueStream::from_stream(
stream.map(move |mut x| match &mut x {
Value::Record { cols, vals, .. } => {
let mut idx = 0;
while idx < cols.len() {
if cols[idx] == "name" {
if let Some(Value::String { val: path, span }) =
vals.get(idx)
{
match std::fs::symlink_metadata(&path) {
Ok(metadata) => {
let style = ls_colors
.style_for_path_with_metadata(
path.clone(),
Some(&metadata),
);
let ansi_style = style
.map(Style::to_crossterm_style)
.unwrap_or_default();
let use_ls_colors = config.use_ls_colors;
if use_ls_colors {
vals[idx] = Value::String {
val: ansi_style
.apply(path)
.to_string(),
span: *span,
};
}
}
Err(_) => {
let style =
ls_colors.style_for_path(path.clone());
let ansi_style = style
.map(Style::to_crossterm_style)
.unwrap_or_default();
let use_ls_colors = config.use_ls_colors;
if use_ls_colors {
vals[idx] = Value::String {
val: ansi_style
.apply(path)
.to_string(),
span: *span,
};
}
}
}
}
}
idx += 1;
}
x
}
_ => x,
}),
ctrlc,
)
}
_ => stream,
};
let table = convert_to_table(stream, ctrlc, &config)?;
if let Some(table) = table {
@ -75,7 +154,7 @@ impl Command for Table {
Ok(PipelineData::new(call.head))
}
}
PipelineData::Value(Value::Record { cols, vals, .. }) => {
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
let mut output = vec![];
for (c, v) in cols.into_iter().zip(vals.into_iter()) {
@ -105,8 +184,8 @@ impl Command for Table {
}
.into_pipeline_data())
}
PipelineData::Value(Value::Error { error }) => Err(error),
PipelineData::Value(Value::CustomValue { val, span }) => {
PipelineData::Value(Value::Error { error }, ..) => Err(error),
PipelineData::Value(Value::CustomValue { val, span }, ..) => {
let base_pipeline = val.to_base_value(span)?.into_pipeline_data();
self.run(engine_state, stack, call, base_pipeline)
}

View File

@ -147,7 +147,7 @@ mod test {
assert!(call.has_flag("flag"));
let required: f64 = call.req(0).unwrap();
assert_eq!(required, 1.0);
assert!((required - 1.0).abs() < f64::EPSILON);
let optional: Option<String> = call.opt(1).unwrap();
assert_eq!(optional, Some("something".to_string()));

View File

@ -145,8 +145,8 @@ impl Command for PluginDeclaration {
})?;
let input = match input {
PipelineData::Value(value) => value,
PipelineData::Stream(stream) => {
PipelineData::Value(value, ..) => value,
PipelineData::Stream(stream, ..) => {
let values = stream.collect::<Vec<Value>>();
Value::List {
@ -192,7 +192,9 @@ impl Command for PluginDeclaration {
})?;
match response {
PluginResponse::Value(value) => Ok(PipelineData::Value(value.as_ref().clone())),
PluginResponse::Value(value) => {
Ok(PipelineData::Value(value.as_ref().clone(), None))
}
PluginResponse::Error(msg) => Err(ShellError::LabeledError(
"Error received from plugin".into(),
msg,

View File

@ -363,8 +363,8 @@ impl EngineState {
let decl = self.get_decl(decl_id);
match input {
PipelineData::Stream(_) => decl,
PipelineData::Value(value) => match value {
PipelineData::Stream(..) => decl,
PipelineData::Value(value, ..) => match value {
Value::CustomValue { val, .. } => {
// This filter works because the custom definitions were declared
// before the default nushell declarations. This means that the custom

View File

@ -33,19 +33,29 @@ use crate::{ast::PathMember, Config, ShellError, Span, Value, ValueStream};
/// Nushell.
#[derive(Debug)]
pub enum PipelineData {
Value(Value),
Stream(ValueStream),
Value(Value, Option<PipelineMetadata>),
Stream(ValueStream, Option<PipelineMetadata>),
}
#[derive(Debug)]
pub struct PipelineMetadata {
pub data_source: DataSource,
}
#[derive(Debug)]
pub enum DataSource {
Ls,
}
impl PipelineData {
pub fn new(span: Span) -> PipelineData {
PipelineData::Value(Value::Nothing { span })
PipelineData::Value(Value::Nothing { span }, None)
}
pub fn into_value(self, span: Span) -> Value {
match self {
PipelineData::Value(v) => v,
PipelineData::Stream(s) => Value::List {
PipelineData::Value(v, ..) => v,
PipelineData::Stream(s, ..) => Value::List {
vals: s.collect(),
span, // FIXME?
},
@ -55,7 +65,7 @@ impl PipelineData {
pub fn into_interruptible_iter(self, ctrlc: Option<Arc<AtomicBool>>) -> PipelineIterator {
let mut iter = self.into_iter();
if let PipelineIterator(PipelineData::Stream(s)) = &mut iter {
if let PipelineIterator(PipelineData::Stream(s, ..)) = &mut iter {
s.ctrlc = ctrlc;
}
@ -64,20 +74,20 @@ impl PipelineData {
pub fn collect_string(self, separator: &str, config: &Config) -> String {
match self {
PipelineData::Value(v) => v.into_string(separator, config),
PipelineData::Stream(s) => s.into_string(separator, config),
PipelineData::Value(v, ..) => v.into_string(separator, config),
PipelineData::Stream(s, ..) => s.into_string(separator, config),
}
}
pub fn follow_cell_path(self, cell_path: &[PathMember]) -> Result<Value, ShellError> {
match self {
// FIXME: there are probably better ways of doing this
PipelineData::Stream(stream) => Value::List {
PipelineData::Stream(stream, ..) => Value::List {
vals: stream.collect(),
span: Span::unknown(),
}
.follow_cell_path(cell_path),
PipelineData::Value(v) => v.follow_cell_path(cell_path),
PipelineData::Value(v, ..) => v.follow_cell_path(cell_path),
}
}
@ -88,12 +98,12 @@ impl PipelineData {
) -> Result<(), ShellError> {
match self {
// FIXME: there are probably better ways of doing this
PipelineData::Stream(stream) => Value::List {
PipelineData::Stream(stream, ..) => Value::List {
vals: stream.collect(),
span: Span::unknown(),
}
.update_cell_path(cell_path, callback),
PipelineData::Value(v) => v.update_cell_path(cell_path, callback),
PipelineData::Value(v, ..) => v.update_cell_path(cell_path, callback),
}
}
@ -108,14 +118,14 @@ impl PipelineData {
F: FnMut(Value) -> Value + 'static + Send,
{
match self {
PipelineData::Value(Value::List { vals, .. }) => {
PipelineData::Value(Value::List { vals, .. }, ..) => {
Ok(vals.into_iter().map(f).into_pipeline_data(ctrlc))
}
PipelineData::Stream(stream) => Ok(stream.map(f).into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Range { val, .. }) => {
PipelineData::Stream(stream, ..) => Ok(stream.map(f).into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Range { val, .. }, ..) => {
Ok(val.into_range_iter()?.map(f).into_pipeline_data(ctrlc))
}
PipelineData::Value(v) => match f(v) {
PipelineData::Value(v, ..) => match f(v) {
Value::Error { error } => Err(error),
v => Ok(v.into_pipeline_data()),
},
@ -135,15 +145,17 @@ impl PipelineData {
F: FnMut(Value) -> U + 'static + Send,
{
match self {
PipelineData::Value(Value::List { vals, .. }) => {
PipelineData::Value(Value::List { vals, .. }, ..) => {
Ok(vals.into_iter().map(f).flatten().into_pipeline_data(ctrlc))
}
PipelineData::Stream(stream) => Ok(stream.map(f).flatten().into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Range { val, .. }) => match val.into_range_iter() {
PipelineData::Stream(stream, ..) => {
Ok(stream.map(f).flatten().into_pipeline_data(ctrlc))
}
PipelineData::Value(Value::Range { val, .. }, ..) => match val.into_range_iter() {
Ok(iter) => Ok(iter.map(f).flatten().into_pipeline_data(ctrlc)),
Err(error) => Err(error),
},
PipelineData::Value(v) => Ok(f(v).into_iter().into_pipeline_data(ctrlc)),
PipelineData::Value(v, ..) => Ok(f(v).into_iter().into_pipeline_data(ctrlc)),
}
}
@ -157,14 +169,14 @@ impl PipelineData {
F: FnMut(&Value) -> bool + 'static + Send,
{
match self {
PipelineData::Value(Value::List { vals, .. }) => {
PipelineData::Value(Value::List { vals, .. }, ..) => {
Ok(vals.into_iter().filter(f).into_pipeline_data(ctrlc))
}
PipelineData::Stream(stream) => Ok(stream.filter(f).into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Range { val, .. }) => {
PipelineData::Stream(stream, ..) => Ok(stream.filter(f).into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Range { val, .. }, ..) => {
Ok(val.into_range_iter()?.filter(f).into_pipeline_data(ctrlc))
}
PipelineData::Value(v) => {
PipelineData::Value(v, ..) => {
if f(&v) {
Ok(v.into_pipeline_data())
} else {
@ -190,22 +202,33 @@ impl IntoIterator for PipelineData {
fn into_iter(self) -> Self::IntoIter {
match self {
PipelineData::Value(Value::List { vals, .. }) => {
PipelineIterator(PipelineData::Stream(ValueStream {
stream: Box::new(vals.into_iter()),
ctrlc: None,
}))
PipelineData::Value(Value::List { vals, .. }, metadata) => {
PipelineIterator(PipelineData::Stream(
ValueStream {
stream: Box::new(vals.into_iter()),
ctrlc: None,
},
metadata,
))
}
PipelineData::Value(Value::Range { val, .. }, metadata) => {
match val.into_range_iter() {
Ok(iter) => PipelineIterator(PipelineData::Stream(
ValueStream {
stream: Box::new(iter),
ctrlc: None,
},
metadata,
)),
Err(error) => PipelineIterator(PipelineData::Stream(
ValueStream {
stream: Box::new(std::iter::once(Value::Error { error })),
ctrlc: None,
},
metadata,
)),
}
}
PipelineData::Value(Value::Range { val, .. }) => match val.into_range_iter() {
Ok(iter) => PipelineIterator(PipelineData::Stream(ValueStream {
stream: Box::new(iter),
ctrlc: None,
})),
Err(error) => PipelineIterator(PipelineData::Stream(ValueStream {
stream: Box::new(std::iter::once(Value::Error { error })),
ctrlc: None,
})),
},
x => PipelineIterator(x),
}
}
@ -216,9 +239,9 @@ impl Iterator for PipelineIterator {
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
PipelineData::Value(Value::Nothing { .. }) => None,
PipelineData::Value(v) => Some(std::mem::take(v)),
PipelineData::Stream(stream) => stream.next(),
PipelineData::Value(Value::Nothing { .. }, ..) => None,
PipelineData::Value(v, ..) => Some(std::mem::take(v)),
PipelineData::Stream(stream, ..) => stream.next(),
}
}
}
@ -232,12 +255,17 @@ where
V: Into<Value>,
{
fn into_pipeline_data(self) -> PipelineData {
PipelineData::Value(self.into())
PipelineData::Value(self.into(), None)
}
}
pub trait IntoInterruptiblePipelineData {
fn into_pipeline_data(self, ctrlc: Option<Arc<AtomicBool>>) -> PipelineData;
fn into_pipeline_data_with_metadata(
self,
metadata: PipelineMetadata,
ctrlc: Option<Arc<AtomicBool>>,
) -> PipelineData;
}
impl<I> IntoInterruptiblePipelineData for I
@ -247,9 +275,26 @@ where
<I::IntoIter as Iterator>::Item: Into<Value>,
{
fn into_pipeline_data(self, ctrlc: Option<Arc<AtomicBool>>) -> PipelineData {
PipelineData::Stream(ValueStream {
stream: Box::new(self.into_iter().map(Into::into)),
ctrlc,
})
PipelineData::Stream(
ValueStream {
stream: Box::new(self.into_iter().map(Into::into)),
ctrlc,
},
None,
)
}
fn into_pipeline_data_with_metadata(
self,
metadata: PipelineMetadata,
ctrlc: Option<Arc<AtomicBool>>,
) -> PipelineData {
PipelineData::Stream(
ValueStream {
stream: Box::new(self.into_iter().map(Into::into)),
ctrlc,
},
Some(metadata),
)
}
}

View File

@ -126,14 +126,14 @@ fn test2(call: &EvaluatedCall, input: &Value) -> Result<Value, ShellError> {
let vals = (0..3)
.map(|v| Value::Int {
val: v * i,
span: call.head.clone(),
span: call.head,
})
.collect::<Vec<Value>>();
Value::Record {
cols: cols.clone(),
vals,
span: call.head.clone(),
span: call.head,
}
})
.collect::<Vec<Value>>();

View File

@ -19,7 +19,7 @@ use nu_parser::parse;
use nu_protocol::{
ast::Call,
engine::{EngineState, Stack, StateWorkingSet},
IntoPipelineData, PipelineData, ShellError, Span, Value, CONFIG_VARIABLE_ID,
PipelineData, ShellError, Span, Value, CONFIG_VARIABLE_ID,
};
use reedline::{Completer, CompletionActionHandler, DefaultPrompt, LineBuffer, Prompt};
@ -313,8 +313,8 @@ fn main() -> Result<()> {
}
}
fn print_value(
value: Value,
fn print_pipeline_data(
input: PipelineData,
engine_state: &EngineState,
stack: &mut Stack,
) -> Result<(), ShellError> {
@ -325,15 +325,13 @@ fn print_value(
let output = match engine_state.find_decl("table".as_bytes()) {
Some(decl_id) => {
let table = engine_state.get_decl(decl_id).run(
engine_state,
stack,
&Call::new(),
value.into_pipeline_data(),
)?;
let table =
engine_state
.get_decl(decl_id)
.run(engine_state, stack, &Call::new(), input)?;
table.collect_string("\n", &config)
}
None => value.into_string(", ", &config),
None => input.collect_string(", ", &config),
};
let stdout = std::io::stdout();
@ -436,11 +434,7 @@ fn eval_source(
PipelineData::new(Span::unknown()),
) {
Ok(pipeline_data) => {
if let Err(err) = print_value(
pipeline_data.into_value(Span::unknown()),
engine_state,
stack,
) {
if let Err(err) = print_pipeline_data(pipeline_data, engine_state, stack) {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &err);