mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 22:47:43 +02:00
Str plugin promoted to built-in Nu command.
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
use indexmap::set::IndexSet;
|
||||
use itertools::Itertools;
|
||||
use nu_errors::{ExpectedRange, ShellError};
|
||||
use nu_protocol::{
|
||||
@ -17,6 +18,11 @@ pub trait ValueExt {
|
||||
path: &ColumnPath,
|
||||
callback: Box<dyn FnOnce((&Value, &PathMember, ShellError)) -> ShellError>,
|
||||
) -> Result<Value, ShellError>;
|
||||
fn swap_data_by_column_path(
|
||||
&self,
|
||||
path: &ColumnPath,
|
||||
callback: Box<dyn FnOnce(&Value) -> Result<Value, ShellError>>,
|
||||
) -> Result<Value, ShellError>;
|
||||
fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option<Value>;
|
||||
fn insert_data_at_member(
|
||||
&mut self,
|
||||
@ -63,6 +69,14 @@ impl ValueExt for Value {
|
||||
get_data_by_column_path(self, path, callback)
|
||||
}
|
||||
|
||||
fn swap_data_by_column_path(
|
||||
&self,
|
||||
path: &ColumnPath,
|
||||
callback: Box<dyn FnOnce(&Value) -> Result<Value, ShellError>>,
|
||||
) -> Result<Value, ShellError> {
|
||||
swap_data_by_column_path(self, path, callback)
|
||||
}
|
||||
|
||||
fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option<Value> {
|
||||
insert_data_at_path(self, path, new_value)
|
||||
}
|
||||
@ -195,6 +209,159 @@ pub fn get_data_by_column_path(
|
||||
Ok(current)
|
||||
}
|
||||
|
||||
pub fn swap_data_by_column_path(
|
||||
value: &Value,
|
||||
path: &ColumnPath,
|
||||
callback: Box<dyn FnOnce(&Value) -> Result<Value, ShellError>>,
|
||||
) -> Result<Value, ShellError> {
|
||||
let fields = path.clone();
|
||||
|
||||
let to_replace = get_data_by_column_path(
|
||||
&value,
|
||||
path,
|
||||
Box::new(move |(obj_source, column_path_tried, error)| {
|
||||
let path_members_span =
|
||||
nu_source::span_for_spanned_list(fields.members().iter().map(|p| p.span));
|
||||
|
||||
match &obj_source.value {
|
||||
UntaggedValue::Table(rows) => match column_path_tried {
|
||||
PathMember {
|
||||
unspanned: UnspannedPathMember::String(column),
|
||||
..
|
||||
} => {
|
||||
let primary_label = format!("There isn't a column named '{}'", &column);
|
||||
|
||||
let suggestions: IndexSet<_> = rows
|
||||
.iter()
|
||||
.filter_map(|r| nu_protocol::did_you_mean(&r, &column_path_tried))
|
||||
.map(|s| s[0].1.to_owned())
|
||||
.collect();
|
||||
let mut existing_columns: IndexSet<_> = IndexSet::default();
|
||||
let mut names: Vec<String> = vec![];
|
||||
|
||||
for row in rows {
|
||||
for field in row.data_descriptors() {
|
||||
if !existing_columns.contains(&field[..]) {
|
||||
existing_columns.insert(field.clone());
|
||||
names.push(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if names.is_empty() {
|
||||
return ShellError::labeled_error_with_secondary(
|
||||
"Unknown column",
|
||||
primary_label,
|
||||
column_path_tried.span,
|
||||
"Appears to contain rows. Try indexing instead.",
|
||||
column_path_tried.span.since(path_members_span),
|
||||
);
|
||||
} else {
|
||||
return ShellError::labeled_error_with_secondary(
|
||||
"Unknown column",
|
||||
primary_label,
|
||||
column_path_tried.span,
|
||||
format!(
|
||||
"Perhaps you meant '{}'? Columns available: {}",
|
||||
suggestions
|
||||
.iter()
|
||||
.map(|x| x.to_owned())
|
||||
.collect::<Vec<String>>()
|
||||
.join(","),
|
||||
names.join(",")
|
||||
),
|
||||
column_path_tried.span.since(path_members_span),
|
||||
);
|
||||
};
|
||||
}
|
||||
PathMember {
|
||||
unspanned: UnspannedPathMember::Int(idx),
|
||||
..
|
||||
} => {
|
||||
let total = rows.len();
|
||||
|
||||
let secondary_label = if total == 1 {
|
||||
"The table only has 1 row".to_owned()
|
||||
} else {
|
||||
format!("The table only has {} rows (0 to {})", total, total - 1)
|
||||
};
|
||||
|
||||
return ShellError::labeled_error_with_secondary(
|
||||
"Row not found",
|
||||
format!("There isn't a row indexed at {}", idx),
|
||||
column_path_tried.span,
|
||||
secondary_label,
|
||||
column_path_tried.span.since(path_members_span),
|
||||
);
|
||||
}
|
||||
},
|
||||
UntaggedValue::Row(columns) => match column_path_tried {
|
||||
PathMember {
|
||||
unspanned: UnspannedPathMember::String(column),
|
||||
..
|
||||
} => {
|
||||
let primary_label = format!("There isn't a column named '{}'", &column);
|
||||
|
||||
if let Some(suggestions) =
|
||||
nu_protocol::did_you_mean(&obj_source, column_path_tried)
|
||||
{
|
||||
return ShellError::labeled_error_with_secondary(
|
||||
"Unknown column",
|
||||
primary_label,
|
||||
column_path_tried.span,
|
||||
format!(
|
||||
"Perhaps you meant '{}'? Columns available: {}",
|
||||
suggestions[0].1,
|
||||
&obj_source.data_descriptors().join(",")
|
||||
),
|
||||
column_path_tried.span.since(path_members_span),
|
||||
);
|
||||
}
|
||||
}
|
||||
PathMember {
|
||||
unspanned: UnspannedPathMember::Int(idx),
|
||||
..
|
||||
} => {
|
||||
return ShellError::labeled_error_with_secondary(
|
||||
"No rows available",
|
||||
format!("A row at '{}' can't be indexed.", &idx),
|
||||
column_path_tried.span,
|
||||
format!(
|
||||
"Appears to contain columns. Columns available: {}",
|
||||
columns.keys().join(",")
|
||||
),
|
||||
column_path_tried.span.since(path_members_span),
|
||||
)
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(suggestions) = nu_protocol::did_you_mean(&obj_source, column_path_tried) {
|
||||
return ShellError::labeled_error(
|
||||
"Unknown column",
|
||||
format!("did you mean '{}'?", suggestions[0].1),
|
||||
column_path_tried.span.since(path_members_span),
|
||||
);
|
||||
}
|
||||
|
||||
error
|
||||
}),
|
||||
);
|
||||
|
||||
let to_replace = to_replace?;
|
||||
let replacement = callback(&to_replace)?;
|
||||
|
||||
match value.replace_data_at_column_path(&path, replacement) {
|
||||
Some(replaced) => Ok(replaced),
|
||||
None => Err(ShellError::labeled_error(
|
||||
"missing column-path",
|
||||
"missing column-path",
|
||||
value.tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_data_at_path(value: &Value, path: &str, new_value: Value) -> Option<Value> {
|
||||
let mut new_obj = value.clone();
|
||||
|
||||
|
Reference in New Issue
Block a user