mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 05:14:44 +02:00
Rows and values can be checked for emptiness. Allows to set a value if desired. (#1665)
This commit is contained in:
committed by
GitHub
parent
a62745eefb
commit
80025ea684
@ -307,6 +307,7 @@ pub fn create_default_context(
|
||||
whole_stream_command(Rename),
|
||||
whole_stream_command(Uniq),
|
||||
per_item_command(Each),
|
||||
per_item_command(IsEmpty),
|
||||
// Table manipulation
|
||||
whole_stream_command(Shuffle),
|
||||
whole_stream_command(Wrap),
|
||||
|
@ -54,6 +54,7 @@ pub(crate) mod help;
|
||||
pub(crate) mod histogram;
|
||||
pub(crate) mod history;
|
||||
pub(crate) mod insert;
|
||||
pub(crate) mod is_empty;
|
||||
pub(crate) mod last;
|
||||
pub(crate) mod lines;
|
||||
pub(crate) mod ls;
|
||||
@ -135,6 +136,7 @@ pub(crate) use du::Du;
|
||||
pub(crate) use each::Each;
|
||||
pub(crate) use echo::Echo;
|
||||
pub(crate) use edit::Edit;
|
||||
pub(crate) use is_empty::IsEmpty;
|
||||
pub(crate) mod kill;
|
||||
pub(crate) use kill::Kill;
|
||||
pub(crate) mod clear;
|
||||
|
203
crates/nu-cli/src/commands/is_empty.rs
Normal file
203
crates/nu-cli/src/commands/is_empty.rs
Normal file
@ -0,0 +1,203 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
CallInfo, ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
use nu_value_ext::ValueExt;
|
||||
|
||||
enum IsEmptyFor {
|
||||
Value,
|
||||
RowWithFieldsAndFallback(Vec<Tagged<ColumnPath>>, Value),
|
||||
RowWithField(Tagged<ColumnPath>),
|
||||
RowWithFieldAndFallback(Box<Tagged<ColumnPath>>, Value),
|
||||
}
|
||||
|
||||
pub struct IsEmpty;
|
||||
|
||||
impl PerItemCommand for IsEmpty {
|
||||
fn name(&self) -> &str {
|
||||
"empty?"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("empty?").rest(
|
||||
SyntaxShape::Any,
|
||||
"the names of the columns to check emptiness followed by the replacement value.",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Checks emptiness. The last value is the replacement value for any empty column(s) given to check against the table."
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
value: Value,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let value_tag = value.tag();
|
||||
|
||||
let action = if call_info.args.len() <= 2 {
|
||||
let field = call_info.args.expect_nth(0);
|
||||
let replacement_if_true = call_info.args.expect_nth(1);
|
||||
|
||||
match (field, replacement_if_true) {
|
||||
(Ok(field), Ok(replacement_if_true)) => IsEmptyFor::RowWithFieldAndFallback(
|
||||
Box::new(field.as_column_path()?),
|
||||
replacement_if_true.clone(),
|
||||
),
|
||||
(Ok(field), Err(_)) => IsEmptyFor::RowWithField(field.as_column_path()?),
|
||||
(_, _) => IsEmptyFor::Value,
|
||||
}
|
||||
} else {
|
||||
let no_args = vec![];
|
||||
let mut arguments = call_info
|
||||
.args
|
||||
.positional
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| &no_args)
|
||||
.iter()
|
||||
.rev();
|
||||
let replacement_if_true = match arguments.next() {
|
||||
Some(arg) => arg.clone(),
|
||||
None => UntaggedValue::boolean(value.is_empty()).into_value(&value_tag),
|
||||
};
|
||||
|
||||
IsEmptyFor::RowWithFieldsAndFallback(
|
||||
arguments
|
||||
.map(|a| a.as_column_path())
|
||||
.filter_map(Result::ok)
|
||||
.collect(),
|
||||
replacement_if_true,
|
||||
)
|
||||
};
|
||||
|
||||
match action {
|
||||
IsEmptyFor::Value => Ok(futures::stream::iter(vec![Ok(ReturnSuccess::Value(
|
||||
UntaggedValue::boolean(value.is_empty()).into_value(value_tag),
|
||||
))])
|
||||
.to_output_stream()),
|
||||
IsEmptyFor::RowWithFieldsAndFallback(fields, default) => {
|
||||
let mut out = value;
|
||||
|
||||
for field in fields.iter() {
|
||||
let val =
|
||||
out.get_data_by_column_path(&field, Box::new(move |(_, _, err)| err))?;
|
||||
|
||||
let emptiness_value = match out {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
if val.is_empty() {
|
||||
match obj.replace_data_at_column_path(&field, default.clone()) {
|
||||
Some(v) => Ok(v),
|
||||
None => Err(ShellError::labeled_error(
|
||||
"empty? could not find place to check emptiness",
|
||||
"column name",
|
||||
&field.tag,
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Ok(obj)
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::labeled_error(
|
||||
"Unrecognized type in stream",
|
||||
"original value",
|
||||
&value_tag,
|
||||
)),
|
||||
};
|
||||
|
||||
out = emptiness_value?;
|
||||
}
|
||||
|
||||
Ok(futures::stream::iter(vec![Ok(ReturnSuccess::Value(out))]).to_output_stream())
|
||||
}
|
||||
IsEmptyFor::RowWithField(field) => {
|
||||
let val =
|
||||
value.get_data_by_column_path(&field, Box::new(move |(_, _, err)| err))?;
|
||||
|
||||
let stream = match &value {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
if val.is_empty() {
|
||||
match obj.replace_data_at_column_path(
|
||||
&field,
|
||||
UntaggedValue::boolean(true).into_value(&value_tag),
|
||||
) {
|
||||
Some(v) => futures::stream::iter(vec![Ok(ReturnSuccess::Value(v))]),
|
||||
None => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"empty? could not find place to check emptiness",
|
||||
"column name",
|
||||
&field.tag,
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
futures::stream::iter(vec![Ok(ReturnSuccess::Value(value))])
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Unrecognized type in stream",
|
||||
"original value",
|
||||
&value_tag,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
IsEmptyFor::RowWithFieldAndFallback(field, default) => {
|
||||
let val =
|
||||
value.get_data_by_column_path(&field, Box::new(move |(_, _, err)| err))?;
|
||||
|
||||
let stream = match &value {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
if val.is_empty() {
|
||||
match obj.replace_data_at_column_path(&field, default) {
|
||||
Some(v) => futures::stream::iter(vec![Ok(ReturnSuccess::Value(v))]),
|
||||
None => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"empty? could not find place to check emptiness",
|
||||
"column name",
|
||||
&field.tag,
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
futures::stream::iter(vec![Ok(ReturnSuccess::Value(value))])
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Unrecognized type in stream",
|
||||
"original value",
|
||||
&value_tag,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
crates/nu-cli/src/env/environment_syncer.rs
vendored
77
crates/nu-cli/src/env/environment_syncer.rs
vendored
@ -58,7 +58,7 @@ impl EnvironmentSyncer {
|
||||
}
|
||||
|
||||
if let Some(variables) = environment.env() {
|
||||
for var in nu_value_ext::row_entries(&variables) {
|
||||
for var in variables.row_entries() {
|
||||
if let Ok(string) = var.1.as_string() {
|
||||
ctx.with_host(|host| {
|
||||
host.env_set(
|
||||
@ -88,7 +88,8 @@ impl EnvironmentSyncer {
|
||||
|
||||
if let Some(new_paths) = environment.path() {
|
||||
let prepared = std::env::join_paths(
|
||||
nu_value_ext::table_entries(&new_paths)
|
||||
new_paths
|
||||
.table_entries()
|
||||
.map(|p| p.as_string())
|
||||
.filter_map(Result::ok),
|
||||
);
|
||||
@ -212,16 +213,17 @@ mod tests {
|
||||
// including the newer one accounted for.
|
||||
let environment = actual.env.lock();
|
||||
|
||||
let vars = nu_value_ext::row_entries(
|
||||
&environment.env().expect("No variables in the environment."),
|
||||
)
|
||||
.map(|(name, value)| {
|
||||
(
|
||||
name.to_string(),
|
||||
value.as_string().expect("Couldn't convert to string"),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let vars = environment
|
||||
.env()
|
||||
.expect("No variables in the environment.")
|
||||
.row_entries()
|
||||
.map(|(name, value)| {
|
||||
(
|
||||
name.to_string(),
|
||||
value.as_string().expect("Couldn't convert to string"),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vars, expected);
|
||||
});
|
||||
@ -281,16 +283,17 @@ mod tests {
|
||||
|
||||
let environment = actual.env.lock();
|
||||
|
||||
let vars = nu_value_ext::row_entries(
|
||||
&environment.env().expect("No variables in the environment."),
|
||||
)
|
||||
.map(|(name, value)| {
|
||||
(
|
||||
name.to_string(),
|
||||
value.as_string().expect("Couldn't convert to string"),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let vars = environment
|
||||
.env()
|
||||
.expect("No variables in the environment.")
|
||||
.row_entries()
|
||||
.map(|(name, value)| {
|
||||
(
|
||||
name.to_string(),
|
||||
value.as_string().expect("Couldn't convert to string"),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vars, expected);
|
||||
});
|
||||
@ -367,14 +370,13 @@ mod tests {
|
||||
let environment = actual.env.lock();
|
||||
|
||||
let paths = std::env::join_paths(
|
||||
&nu_value_ext::table_entries(
|
||||
&environment
|
||||
.path()
|
||||
.expect("No path variable in the environment."),
|
||||
)
|
||||
.map(|value| value.as_string().expect("Couldn't convert to string"))
|
||||
.map(PathBuf::from)
|
||||
.collect::<Vec<_>>(),
|
||||
&environment
|
||||
.path()
|
||||
.expect("No path variable in the environment.")
|
||||
.table_entries()
|
||||
.map(|value| value.as_string().expect("Couldn't convert to string"))
|
||||
.map(PathBuf::from)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.expect("Couldn't join paths.")
|
||||
.into_string()
|
||||
@ -442,14 +444,13 @@ mod tests {
|
||||
let environment = actual.env.lock();
|
||||
|
||||
let paths = std::env::join_paths(
|
||||
&nu_value_ext::table_entries(
|
||||
&environment
|
||||
.path()
|
||||
.expect("No path variable in the environment."),
|
||||
)
|
||||
.map(|value| value.as_string().expect("Couldn't convert to string"))
|
||||
.map(PathBuf::from)
|
||||
.collect::<Vec<_>>(),
|
||||
&environment
|
||||
.path()
|
||||
.expect("No path variable in the environment.")
|
||||
.table_entries()
|
||||
.map(|value| value.as_string().expect("Couldn't convert to string"))
|
||||
.map(PathBuf::from)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.expect("Couldn't join paths.")
|
||||
.into_string()
|
||||
|
@ -69,7 +69,7 @@ impl ValueStructure {
|
||||
}
|
||||
|
||||
fn build(&mut self, src: &Value, lvl: usize) -> Result<(), ShellError> {
|
||||
for entry in nu_value_ext::row_entries(src) {
|
||||
for entry in src.row_entries() {
|
||||
let value = entry.1;
|
||||
let path = entry.0;
|
||||
|
||||
|
Reference in New Issue
Block a user