mirror of
https://github.com/nushell/nushell.git
synced 2024-11-07 17:14:23 +01:00
Introduce metadata into the pipeline (#397)
This commit is contained in:
parent
56307553ae
commit
45eba8b922
@ -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,
|
||||
),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
)),
|
||||
|
@ -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) {
|
||||
|
@ -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()))
|
||||
|
@ -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![];
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)]
|
||||
|
@ -194,7 +194,7 @@ fn from_ods(
|
||||
span: head,
|
||||
};
|
||||
|
||||
Ok(PipelineData::Value(record))
|
||||
Ok(PipelineData::Value(record, None))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -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(),
|
||||
|
@ -194,7 +194,7 @@ fn from_xlsx(
|
||||
span: head,
|
||||
};
|
||||
|
||||
Ok(PipelineData::Value(record))
|
||||
Ok(PipelineData::Value(record, None))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -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(
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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)]
|
||||
|
@ -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(),
|
||||
|
@ -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> {
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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![];
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()));
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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>>();
|
||||
|
24
src/main.rs
24
src/main.rs
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user