mirror of
https://github.com/nushell/nushell
synced 2024-12-28 14:03:09 +00:00
Remove lazy records (#12682)
# Description Removes lazy records from the language, following from the reasons outlined in #12622. Namely, this should make semantics more clear and will eliminate concerns regarding maintainability. # User-Facing Changes - Breaking change: `lazy make` is removed. - Breaking change: `describe --collect-lazyrecords` flag is removed. - `sys` and `debug info` now return regular records. # After Submitting - Update nushell book if necessary. - Explore new `sys` and `debug info` APIs to prevent them from taking too long (e.g., subcommands or taking an optional column/cell-path argument).
This commit is contained in:
parent
ad6deadf24
commit
847646e44e
32 changed files with 133 additions and 867 deletions
|
@ -267,24 +267,6 @@ fn nested_suggestions(
|
||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
// Add all the columns as completion
|
|
||||||
for column_name in val.column_names() {
|
|
||||||
output.push(SemanticSuggestion {
|
|
||||||
suggestion: Suggestion {
|
|
||||||
value: column_name.to_string(),
|
|
||||||
description: None,
|
|
||||||
style: None,
|
|
||||||
extra: None,
|
|
||||||
span: current_span,
|
|
||||||
append_whitespace: false,
|
|
||||||
},
|
|
||||||
kind: Some(kind.clone()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
Value::List { vals, .. } => {
|
Value::List { vals, .. } => {
|
||||||
for column_name in get_columns(vals.as_slice()) {
|
for column_name in get_columns(vals.as_slice()) {
|
||||||
output.push(SemanticSuggestion {
|
output.push(SemanticSuggestion {
|
||||||
|
@ -321,17 +303,6 @@ fn recursive_value(val: &Value, sublevels: &[Vec<u8>]) -> Result<Value, Span> {
|
||||||
Err(span)
|
Err(span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
for col in val.column_names() {
|
|
||||||
if col.as_bytes() == *sublevel {
|
|
||||||
let val = val.get_column_value(col).map_err(|_| span)?;
|
|
||||||
return recursive_value(&val, next_sublevels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Current sublevel value not found
|
|
||||||
Err(span)
|
|
||||||
}
|
|
||||||
Value::List { vals, .. } => {
|
Value::List { vals, .. } => {
|
||||||
for col in get_columns(vals.as_slice()) {
|
for col in get_columns(vals.as_slice()) {
|
||||||
if col.as_bytes() == *sublevel {
|
if col.as_bytes() == *sublevel {
|
||||||
|
|
|
@ -26,7 +26,6 @@ impl Command for Describe {
|
||||||
"show detailed information about the value",
|
"show detailed information about the value",
|
||||||
Some('d'),
|
Some('d'),
|
||||||
)
|
)
|
||||||
.switch("collect-lazyrecords", "collect lazy records", Some('l'))
|
|
||||||
.category(Category::Core)
|
.category(Category::Core)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,21 +43,7 @@ impl Command for Describe {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
no_collect: call.has_flag(engine_state, stack, "no-collect")?,
|
no_collect: call.has_flag(engine_state, stack, "no-collect")?,
|
||||||
detailed: call.has_flag(engine_state, stack, "detailed")?,
|
detailed: call.has_flag(engine_state, stack, "detailed")?,
|
||||||
collect_lazyrecords: call.has_flag(engine_state, stack, "collect-lazyrecords")?,
|
|
||||||
};
|
};
|
||||||
if options.collect_lazyrecords {
|
|
||||||
nu_protocol::report_error_new(
|
|
||||||
engine_state,
|
|
||||||
&ShellError::GenericError {
|
|
||||||
error: "Deprecated flag".into(),
|
|
||||||
msg: "the `--collect-lazyrecords` flag is deprecated, since lazy records will be removed in 0.94.0"
|
|
||||||
.into(),
|
|
||||||
span: Some(call.head),
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
run(Some(engine_state), call, input, options)
|
run(Some(engine_state), call, input, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +56,6 @@ impl Command for Describe {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
no_collect: call.has_flag_const(working_set, "no-collect")?,
|
no_collect: call.has_flag_const(working_set, "no-collect")?,
|
||||||
detailed: call.has_flag_const(working_set, "detailed")?,
|
detailed: call.has_flag_const(working_set, "detailed")?,
|
||||||
collect_lazyrecords: call.has_flag_const(working_set, "collect-lazyrecords")?,
|
|
||||||
};
|
};
|
||||||
run(None, call, input, options)
|
run(None, call, input, options)
|
||||||
}
|
}
|
||||||
|
@ -89,13 +73,11 @@ impl Command for Describe {
|
||||||
"{shell:'true', uwu:true, features: {bugs:false, multiplatform:true, speed: 10}, fib: [1 1 2 3 5 8], on_save: {|x| print $'Saving ($x)'}, first_commit: 2019-05-10, my_duration: (4min + 20sec)} | describe -d",
|
"{shell:'true', uwu:true, features: {bugs:false, multiplatform:true, speed: 10}, fib: [1 1 2 3 5 8], on_save: {|x| print $'Saving ($x)'}, first_commit: 2019-05-10, my_duration: (4min + 20sec)} | describe -d",
|
||||||
result: Some(Value::test_record(record!(
|
result: Some(Value::test_record(record!(
|
||||||
"type" => Value::test_string("record"),
|
"type" => Value::test_string("record"),
|
||||||
"lazy" => Value::test_bool(false),
|
|
||||||
"columns" => Value::test_record(record!(
|
"columns" => Value::test_record(record!(
|
||||||
"shell" => Value::test_string("string"),
|
"shell" => Value::test_string("string"),
|
||||||
"uwu" => Value::test_string("bool"),
|
"uwu" => Value::test_string("bool"),
|
||||||
"features" => Value::test_record(record!(
|
"features" => Value::test_record(record!(
|
||||||
"type" => Value::test_string("record"),
|
"type" => Value::test_string("record"),
|
||||||
"lazy" => Value::test_bool(false),
|
|
||||||
"columns" => Value::test_record(record!(
|
"columns" => Value::test_record(record!(
|
||||||
"bugs" => Value::test_string("bool"),
|
"bugs" => Value::test_string("bool"),
|
||||||
"multiplatform" => Value::test_string("bool"),
|
"multiplatform" => Value::test_string("bool"),
|
||||||
|
@ -168,7 +150,6 @@ impl Command for Describe {
|
||||||
struct Options {
|
struct Options {
|
||||||
no_collect: bool,
|
no_collect: bool,
|
||||||
detailed: bool,
|
detailed: bool,
|
||||||
collect_lazyrecords: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -243,7 +224,7 @@ fn run(
|
||||||
if options.no_collect {
|
if options.no_collect {
|
||||||
Value::string("any", head)
|
Value::string("any", head)
|
||||||
} else {
|
} else {
|
||||||
describe_value(input.into_value(head), head, engine_state, options)?
|
describe_value(input.into_value(head), head, engine_state, )
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"metadata" => metadata_to_value(metadata, head),
|
"metadata" => metadata_to_value(metadata, head),
|
||||||
|
@ -264,7 +245,7 @@ fn run(
|
||||||
if !options.detailed {
|
if !options.detailed {
|
||||||
Value::string(value.get_type().to_string(), head)
|
Value::string(value.get_type().to_string(), head)
|
||||||
} else {
|
} else {
|
||||||
describe_value(value, head, engine_state, options)?
|
describe_value(value, head, engine_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -288,9 +269,8 @@ fn describe_value(
|
||||||
value: Value,
|
value: Value,
|
||||||
head: nu_protocol::Span,
|
head: nu_protocol::Span,
|
||||||
engine_state: Option<&EngineState>,
|
engine_state: Option<&EngineState>,
|
||||||
options: Options,
|
) -> Value {
|
||||||
) -> Result<Value, ShellError> {
|
match value {
|
||||||
Ok(match value {
|
|
||||||
Value::Custom { val, .. } => Value::record(
|
Value::Custom { val, .. } => Value::record(
|
||||||
record!(
|
record!(
|
||||||
"type" => Value::string("custom", head),
|
"type" => Value::string("custom", head),
|
||||||
|
@ -320,14 +300,12 @@ fn describe_value(
|
||||||
std::mem::take(v),
|
std::mem::take(v),
|
||||||
head,
|
head,
|
||||||
engine_state,
|
engine_state,
|
||||||
options,
|
));
|
||||||
)?);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::record(
|
Value::record(
|
||||||
record!(
|
record!(
|
||||||
"type" => Value::string("record", head),
|
"type" => Value::string("record", head),
|
||||||
"lazy" => Value::bool(false, head),
|
|
||||||
"columns" => Value::record(val, head),
|
"columns" => Value::record(val, head),
|
||||||
),
|
),
|
||||||
head,
|
head,
|
||||||
|
@ -338,11 +316,9 @@ fn describe_value(
|
||||||
"type" => Value::string("list", head),
|
"type" => Value::string("list", head),
|
||||||
"length" => Value::int(vals.len() as i64, head),
|
"length" => Value::int(vals.len() as i64, head),
|
||||||
"values" => Value::list(vals.into_iter().map(|v|
|
"values" => Value::list(vals.into_iter().map(|v|
|
||||||
Ok(compact_primitive_description(
|
compact_primitive_description(describe_value(v, head, engine_state))
|
||||||
describe_value(v, head, engine_state, options)?
|
|
||||||
))
|
|
||||||
)
|
)
|
||||||
.collect::<Result<Vec<Value>, ShellError>>()?, head),
|
.collect(), head),
|
||||||
),
|
),
|
||||||
head,
|
head,
|
||||||
),
|
),
|
||||||
|
@ -394,42 +370,7 @@ fn describe_value(
|
||||||
),
|
),
|
||||||
head,
|
head,
|
||||||
),
|
),
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
let mut record = Record::new();
|
|
||||||
|
|
||||||
record.push("type", Value::string("record", head));
|
|
||||||
record.push("lazy", Value::bool(true, head));
|
|
||||||
|
|
||||||
if options.collect_lazyrecords {
|
|
||||||
let collected = val.collect()?;
|
|
||||||
if let Value::Record { val, .. } =
|
|
||||||
describe_value(collected, head, engine_state, options)?
|
|
||||||
{
|
|
||||||
let mut val = Record::clone(&val);
|
|
||||||
|
|
||||||
for (_k, v) in val.iter_mut() {
|
|
||||||
*v = compact_primitive_description(describe_value(
|
|
||||||
std::mem::take(v),
|
|
||||||
head,
|
|
||||||
engine_state,
|
|
||||||
options,
|
|
||||||
)?);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
record.push("length", Value::int(val.len() as i64, head));
|
|
||||||
record.push("columns", Value::record(val, head));
|
|
||||||
} else {
|
|
||||||
let cols = val.column_names();
|
|
||||||
record.push("length", Value::int(cols.len() as i64, head));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let cols = val.column_names();
|
|
||||||
record.push("length", Value::int(cols.len() as i64, head));
|
|
||||||
}
|
|
||||||
|
|
||||||
Value::record(record, head)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn metadata_to_value(metadata: Option<Box<PipelineMetadata>>, head: nu_protocol::Span) -> Value {
|
fn metadata_to_value(metadata: Option<Box<PipelineMetadata>>, head: nu_protocol::Span) -> Value {
|
||||||
|
|
|
@ -1,179 +0,0 @@
|
||||||
use nu_engine::{command_prelude::*, eval_block};
|
|
||||||
use nu_protocol::{debugger::WithoutDebug, engine::Closure, LazyRecord};
|
|
||||||
use std::{
|
|
||||||
collections::{hash_map::Entry, HashMap},
|
|
||||||
sync::{Arc, Mutex},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct LazyMake;
|
|
||||||
|
|
||||||
impl Command for LazyMake {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"lazy make"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("lazy make")
|
|
||||||
.input_output_types(vec![(Type::Nothing, Type::record())])
|
|
||||||
.required_named(
|
|
||||||
"columns",
|
|
||||||
SyntaxShape::List(Box::new(SyntaxShape::String)),
|
|
||||||
"Closure that gets called when the LazyRecord needs to list the available column names",
|
|
||||||
Some('c')
|
|
||||||
)
|
|
||||||
.required_named(
|
|
||||||
"get-value",
|
|
||||||
SyntaxShape::Closure(Some(vec![SyntaxShape::String])),
|
|
||||||
"Closure to call when a value needs to be produced on demand",
|
|
||||||
Some('g')
|
|
||||||
)
|
|
||||||
.category(Category::Core)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Create a lazy record."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
|
||||||
"Lazy records are special records that only evaluate their values once the property is requested.
|
|
||||||
For example, when printing a lazy record, all of its fields will be collected. But when accessing
|
|
||||||
a specific property, only it will be evaluated.
|
|
||||||
|
|
||||||
Note that this is unrelated to the lazyframes feature bundled with dataframes."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
|
||||||
vec!["deferred", "record", "procedural"]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
nu_protocol::report_error_new(
|
|
||||||
engine_state,
|
|
||||||
&ShellError::GenericError {
|
|
||||||
error: "Deprecated command".into(),
|
|
||||||
msg: "warning: lazy records and the `lazy make` command will be removed in 0.94.0"
|
|
||||||
.into(),
|
|
||||||
span: Some(call.head),
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let span = call.head;
|
|
||||||
let columns: Vec<Spanned<String>> = call
|
|
||||||
.get_flag(engine_state, stack, "columns")?
|
|
||||||
.expect("required flag");
|
|
||||||
|
|
||||||
let get_value: Closure = call
|
|
||||||
.get_flag(engine_state, stack, "get-value")?
|
|
||||||
.expect("required flag");
|
|
||||||
|
|
||||||
let mut unique = HashMap::with_capacity(columns.len());
|
|
||||||
|
|
||||||
for col in &columns {
|
|
||||||
match unique.entry(&col.item) {
|
|
||||||
Entry::Occupied(entry) => {
|
|
||||||
return Err(ShellError::ColumnDefinedTwice {
|
|
||||||
col_name: col.item.clone(),
|
|
||||||
second_use: col.span,
|
|
||||||
first_use: *entry.get(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Entry::Vacant(entry) => {
|
|
||||||
entry.insert(col.span);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let stack = stack.clone().reset_out_dest().capture();
|
|
||||||
|
|
||||||
Ok(Value::lazy_record(
|
|
||||||
Box::new(NuLazyRecord {
|
|
||||||
engine_state: engine_state.clone(),
|
|
||||||
stack: Arc::new(Mutex::new(stack)),
|
|
||||||
columns: columns.into_iter().map(|s| s.item).collect(),
|
|
||||||
get_value,
|
|
||||||
span,
|
|
||||||
}),
|
|
||||||
span,
|
|
||||||
)
|
|
||||||
.into_pipeline_data())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
// TODO: Figure out how to "test" these examples, or leave results as None
|
|
||||||
Example {
|
|
||||||
description: "Create a lazy record",
|
|
||||||
example: r#"lazy make --columns ["haskell", "futures", "nushell"] --get-value { |lazything| $lazything + "!" }"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Test the laziness of lazy records",
|
|
||||||
example: r#"lazy make --columns ["hello"] --get-value { |key| print $"getting ($key)!"; $key | str upcase }"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct NuLazyRecord {
|
|
||||||
engine_state: EngineState,
|
|
||||||
stack: Arc<Mutex<Stack>>,
|
|
||||||
columns: Vec<String>,
|
|
||||||
get_value: Closure,
|
|
||||||
span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for NuLazyRecord {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.debug_struct("NuLazyRecord").finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> LazyRecord<'a> for NuLazyRecord {
|
|
||||||
fn column_names(&'a self) -> Vec<&'a str> {
|
|
||||||
self.columns.iter().map(|column| column.as_str()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_column_value(&self, column: &str) -> Result<Value, ShellError> {
|
|
||||||
let block = self.engine_state.get_block(self.get_value.block_id);
|
|
||||||
let mut stack = self.stack.lock().expect("lock must not be poisoned");
|
|
||||||
let column_value = Value::string(column, self.span);
|
|
||||||
|
|
||||||
if let Some(var) = block.signature.get_positional(0) {
|
|
||||||
if let Some(var_id) = &var.var_id {
|
|
||||||
stack.add_var(*var_id, column_value.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let pipeline_result = eval_block::<WithoutDebug>(
|
|
||||||
&self.engine_state,
|
|
||||||
&mut stack,
|
|
||||||
block,
|
|
||||||
PipelineData::Value(column_value, None),
|
|
||||||
);
|
|
||||||
|
|
||||||
pipeline_result.map(|data| match data {
|
|
||||||
PipelineData::Value(value, ..) => value,
|
|
||||||
// TODO: Proper error handling.
|
|
||||||
_ => Value::nothing(self.span),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn span(&self) -> Span {
|
|
||||||
self.span
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone_value(&self, span: Span) -> Value {
|
|
||||||
Value::lazy_record(Box::new((*self).clone()), span)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,7 +21,6 @@ mod hide;
|
||||||
mod hide_env;
|
mod hide_env;
|
||||||
mod if_;
|
mod if_;
|
||||||
mod ignore;
|
mod ignore;
|
||||||
mod lazy_make;
|
|
||||||
mod let_;
|
mod let_;
|
||||||
mod loop_;
|
mod loop_;
|
||||||
mod match_;
|
mod match_;
|
||||||
|
@ -58,7 +57,6 @@ pub use hide::Hide;
|
||||||
pub use hide_env::HideEnv;
|
pub use hide_env::HideEnv;
|
||||||
pub use if_::If;
|
pub use if_::If;
|
||||||
pub use ignore::Ignore;
|
pub use ignore::Ignore;
|
||||||
pub use lazy_make::LazyMake;
|
|
||||||
pub use let_::Let;
|
pub use let_::Let;
|
||||||
pub use loop_::Loop;
|
pub use loop_::Loop;
|
||||||
pub use match_::Match;
|
pub use match_::Match;
|
||||||
|
|
|
@ -43,7 +43,6 @@ pub fn create_default_context() -> EngineState {
|
||||||
OverlayList,
|
OverlayList,
|
||||||
OverlayNew,
|
OverlayNew,
|
||||||
OverlayHide,
|
OverlayHide,
|
||||||
LazyMake,
|
|
||||||
Let,
|
Let,
|
||||||
Loop,
|
Loop,
|
||||||
Match,
|
Match,
|
||||||
|
|
|
@ -306,10 +306,6 @@ impl<'a> std::fmt::Debug for DebuggableValue<'a> {
|
||||||
Value::Custom { val, .. } => {
|
Value::Custom { val, .. } => {
|
||||||
write!(f, "CustomValue({:?})", val)
|
write!(f, "CustomValue({:?})", val)
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
let rec = val.collect().map_err(|_| std::fmt::Error)?;
|
|
||||||
write!(f, "LazyRecord({:?})", DebuggableValue(&rec))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,10 +106,9 @@ impl<'a> StyleComputer<'a> {
|
||||||
Value::Binary { .. } => TextStyle::with_style(Left, s),
|
Value::Binary { .. } => TextStyle::with_style(Left, s),
|
||||||
Value::CellPath { .. } => TextStyle::with_style(Left, s),
|
Value::CellPath { .. } => TextStyle::with_style(Left, s),
|
||||||
Value::Record { .. } | Value::List { .. } => TextStyle::with_style(Left, s),
|
Value::Record { .. } | Value::List { .. } => TextStyle::with_style(Left, s),
|
||||||
Value::Closure { .. }
|
Value::Closure { .. } | Value::Custom { .. } | Value::Error { .. } => {
|
||||||
| Value::Custom { .. }
|
TextStyle::basic_left()
|
||||||
| Value::Error { .. }
|
}
|
||||||
| Value::LazyRecord { .. } => TextStyle::basic_left(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -272,10 +272,6 @@ pub fn debug_string_without_formatting(value: &Value) -> String {
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(" ")
|
.join(" ")
|
||||||
),
|
),
|
||||||
Value::LazyRecord { val, .. } => match val.collect() {
|
|
||||||
Ok(val) => debug_string_without_formatting(&val),
|
|
||||||
Err(error) => format!("{error:?}"),
|
|
||||||
},
|
|
||||||
//TODO: It would be good to drill deeper into closures.
|
//TODO: It would be good to drill deeper into closures.
|
||||||
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
||||||
Value::Nothing { .. } => String::new(),
|
Value::Nothing { .. } => String::new(),
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::LazyRecord;
|
|
||||||
use sysinfo::{MemoryRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System};
|
use sysinfo::{MemoryRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System};
|
||||||
|
|
||||||
const ENV_PATH_SEPARATOR_CHAR: char = {
|
const ENV_PATH_SEPARATOR_CHAR: char = {
|
||||||
|
@ -39,14 +38,10 @@ impl Command for DebugInfo {
|
||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
_call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let span = Span::unknown();
|
Ok(all_columns(call.head).into_pipeline_data())
|
||||||
|
|
||||||
let record = LazySystemInfoRecord { span };
|
|
||||||
|
|
||||||
Ok(Value::lazy_record(Box::new(record), span).into_pipeline_data())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -58,93 +53,52 @@ impl Command for DebugInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
fn all_columns(span: Span) -> Value {
|
||||||
struct LazySystemInfoRecord {
|
let rk = RefreshKind::new()
|
||||||
span: Span,
|
.with_processes(ProcessRefreshKind::everything())
|
||||||
}
|
.with_memory(MemoryRefreshKind::everything());
|
||||||
|
|
||||||
|
// only get information requested
|
||||||
|
let sys = System::new_with_specifics(rk);
|
||||||
|
|
||||||
impl LazySystemInfoRecord {
|
|
||||||
fn get_column_value_with_system(
|
|
||||||
&self,
|
|
||||||
column: &str,
|
|
||||||
system_option: Option<&System>,
|
|
||||||
) -> Result<Value, ShellError> {
|
|
||||||
let pid = Pid::from(std::process::id() as usize);
|
let pid = Pid::from(std::process::id() as usize);
|
||||||
match column {
|
let ppid = {
|
||||||
"thread_id" => Ok(Value::int(get_thread_id() as i64, self.span)),
|
sys.process(pid)
|
||||||
"pid" => Ok(Value::int(pid.as_u32() as i64, self.span)),
|
|
||||||
"ppid" => {
|
|
||||||
// only get information requested
|
|
||||||
let system_opt = SystemOpt::from((system_option, || {
|
|
||||||
RefreshKind::new().with_processes(ProcessRefreshKind::everything())
|
|
||||||
}));
|
|
||||||
|
|
||||||
let system = system_opt.get_system();
|
|
||||||
// get the process information for the nushell pid
|
|
||||||
let pinfo = system.process(pid);
|
|
||||||
|
|
||||||
Ok(pinfo
|
|
||||||
.and_then(|p| p.parent())
|
.and_then(|p| p.parent())
|
||||||
.map(|p| Value::int(p.as_u32() as i64, self.span))
|
.map(|p| Value::int(p.as_u32().into(), span))
|
||||||
.unwrap_or(Value::nothing(self.span)))
|
.unwrap_or(Value::nothing(span))
|
||||||
}
|
};
|
||||||
"system" => {
|
|
||||||
// only get information requested
|
|
||||||
let system_opt = SystemOpt::from((system_option, || {
|
|
||||||
RefreshKind::new().with_memory(MemoryRefreshKind::everything())
|
|
||||||
}));
|
|
||||||
|
|
||||||
let system = system_opt.get_system();
|
let system = Value::record(
|
||||||
|
|
||||||
Ok(Value::record(
|
|
||||||
record! {
|
record! {
|
||||||
"total_memory" => Value::filesize(system.total_memory() as i64, self.span),
|
"total_memory" => Value::filesize(sys.total_memory() as i64, span),
|
||||||
"free_memory" => Value::filesize(system.free_memory() as i64, self.span),
|
"free_memory" => Value::filesize(sys.free_memory() as i64, span),
|
||||||
"used_memory" => Value::filesize(system.used_memory() as i64, self.span),
|
"used_memory" => Value::filesize(sys.used_memory() as i64, span),
|
||||||
"available_memory" => Value::filesize(system.available_memory() as i64, self.span),
|
"available_memory" => Value::filesize(sys.available_memory() as i64, span),
|
||||||
},
|
},
|
||||||
self.span,
|
span,
|
||||||
))
|
);
|
||||||
}
|
|
||||||
"process" => {
|
|
||||||
// only get information requested
|
|
||||||
let system_opt = SystemOpt::from((system_option, || {
|
|
||||||
RefreshKind::new().with_processes(ProcessRefreshKind::everything())
|
|
||||||
}));
|
|
||||||
|
|
||||||
let system = system_opt.get_system();
|
let process = if let Some(p) = sys.process(pid) {
|
||||||
let pinfo = system.process(pid);
|
let root = if let Some(path) = p.exe().and_then(|p| p.parent()) {
|
||||||
|
Value::string(path.to_string_lossy().to_string(), span)
|
||||||
|
} else {
|
||||||
|
Value::nothing(span)
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(p) = pinfo {
|
let cwd = if let Some(path) = p.cwd() {
|
||||||
Ok(Value::record(
|
Value::string(path.to_string_lossy().to_string(), span)
|
||||||
record! {
|
|
||||||
"memory" => Value::filesize(p.memory() as i64, self.span),
|
|
||||||
"virtual_memory" => Value::filesize(p.virtual_memory() as i64, self.span),
|
|
||||||
"status" => Value::string(p.status().to_string(), self.span),
|
|
||||||
"root" => {
|
|
||||||
if let Some(path) = p.exe().and_then(|p| p.parent()) {
|
|
||||||
Value::string(path.to_string_lossy().to_string(), self.span)
|
|
||||||
} else {
|
} else {
|
||||||
Value::nothing(self.span)
|
Value::nothing(span)
|
||||||
}
|
};
|
||||||
},
|
|
||||||
"cwd" => {
|
let exe_path = if let Some(path) = p.exe() {
|
||||||
if let Some(path) = p.cwd() {
|
Value::string(path.to_string_lossy().to_string(), span)
|
||||||
Value::string(path.to_string_lossy().to_string(), self.span)
|
|
||||||
} else {
|
} else {
|
||||||
Value::nothing(self.span)
|
Value::nothing(span)
|
||||||
}
|
};
|
||||||
},
|
|
||||||
"exe_path" => {
|
let environment = {
|
||||||
if let Some(path)= p.exe() {
|
|
||||||
Value::string(path.to_string_lossy().to_string(), self.span)
|
|
||||||
}else{
|
|
||||||
Value::nothing(self.span)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"command" => Value::string(p.cmd().join(" "), self.span),
|
|
||||||
"name" => Value::string(p.name().to_string(), self.span),
|
|
||||||
"environment" => {
|
|
||||||
let mut env_rec = Record::new();
|
let mut env_rec = Record::new();
|
||||||
for val in p.environ() {
|
for val in p.environ() {
|
||||||
if let Some((key, value)) = val.split_once('=') {
|
if let Some((key, value)) = val.split_once('=') {
|
||||||
|
@ -152,7 +106,10 @@ impl LazySystemInfoRecord {
|
||||||
{
|
{
|
||||||
#[cfg(target_family = "windows")]
|
#[cfg(target_family = "windows")]
|
||||||
{
|
{
|
||||||
key == "Path" || key == "PATHEXT" || key == "PSMODULEPATH" || key == "PSModulePath"
|
key == "Path"
|
||||||
|
|| key == "PATHEXT"
|
||||||
|
|| key == "PSMODULEPATH"
|
||||||
|
|| key == "PSModulePath"
|
||||||
}
|
}
|
||||||
#[cfg(not(target_family = "windows"))]
|
#[cfg(not(target_family = "windows"))]
|
||||||
{
|
{
|
||||||
|
@ -161,104 +118,54 @@ impl LazySystemInfoRecord {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if is_env_var_a_list {
|
if is_env_var_a_list {
|
||||||
let items = value.split(ENV_PATH_SEPARATOR_CHAR).map(|r| Value::string(r.to_string(), self.span)).collect::<Vec<_>>();
|
let items = value
|
||||||
env_rec.push(key.to_string(), Value::list(items, self.span));
|
.split(ENV_PATH_SEPARATOR_CHAR)
|
||||||
} else if key == "LS_COLORS" { // LS_COLORS is a special case, it's a colon separated list of key=value pairs
|
.map(|r| Value::string(r.to_string(), span))
|
||||||
let items = value.split(':').map(|r| Value::string(r.to_string(), self.span)).collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
env_rec.push(key.to_string(), Value::list(items, self.span));
|
env_rec.push(key.to_string(), Value::list(items, span));
|
||||||
|
} else if key == "LS_COLORS" {
|
||||||
|
// LS_COLORS is a special case, it's a colon separated list of key=value pairs
|
||||||
|
let items = value
|
||||||
|
.split(':')
|
||||||
|
.map(|r| Value::string(r.to_string(), span))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
env_rec.push(key.to_string(), Value::list(items, span));
|
||||||
} else {
|
} else {
|
||||||
env_rec.push(key.to_string(), Value::string(value.to_string(), self.span));
|
env_rec.push(key.to_string(), Value::string(value.to_string(), span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::record(env_rec, self.span)
|
Value::record(env_rec, span)
|
||||||
},
|
};
|
||||||
},
|
|
||||||
self.span,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
// If we can't get the process information, just return the system information
|
|
||||||
// only get information requested
|
|
||||||
let system_opt = SystemOpt::from((system_option, || {
|
|
||||||
RefreshKind::new().with_memory(MemoryRefreshKind::everything())
|
|
||||||
}));
|
|
||||||
let system = system_opt.get_system();
|
|
||||||
|
|
||||||
Ok(Value::record(
|
Value::record(
|
||||||
record! {
|
record! {
|
||||||
"total_memory" => Value::filesize(system.total_memory() as i64, self.span),
|
"memory" => Value::filesize(p.memory() as i64, span),
|
||||||
"free_memory" => Value::filesize(system.free_memory() as i64, self.span),
|
"virtual_memory" => Value::filesize(p.virtual_memory() as i64, span),
|
||||||
"used_memory" => Value::filesize(system.used_memory() as i64, self.span),
|
"status" => Value::string(p.status().to_string(), span),
|
||||||
"available_memory" => Value::filesize(system.available_memory() as i64, self.span),
|
"root" => root,
|
||||||
|
"cwd" => cwd,
|
||||||
|
"exe_path" => exe_path,
|
||||||
|
"command" => Value::string(p.cmd().join(" "), span),
|
||||||
|
"name" => Value::string(p.name(), span),
|
||||||
|
"environment" => environment,
|
||||||
},
|
},
|
||||||
self.span,
|
span,
|
||||||
))
|
)
|
||||||
}
|
} else {
|
||||||
}
|
Value::nothing(span)
|
||||||
_ => Err(ShellError::IncompatibleParametersSingle {
|
};
|
||||||
msg: format!("Unknown column: {}", column),
|
|
||||||
span: self.span,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> LazyRecord<'a> for LazySystemInfoRecord {
|
Value::record(
|
||||||
fn column_names(&'a self) -> Vec<&'a str> {
|
record! {
|
||||||
vec!["thread_id", "pid", "ppid", "process", "system"]
|
"thread_id" => Value::int(get_thread_id() as i64, span),
|
||||||
}
|
"pid" => Value::int(pid.as_u32().into(), span),
|
||||||
|
"ppid" => ppid,
|
||||||
fn get_column_value(&self, column: &str) -> Result<Value, ShellError> {
|
"system" => system,
|
||||||
self.get_column_value_with_system(column, None)
|
"process" => process,
|
||||||
}
|
},
|
||||||
|
span,
|
||||||
fn span(&self) -> Span {
|
)
|
||||||
self.span
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone_value(&self, span: Span) -> Value {
|
|
||||||
Value::lazy_record(Box::new(LazySystemInfoRecord { span }), span)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect(&'a self) -> Result<Value, ShellError> {
|
|
||||||
let rk = RefreshKind::new()
|
|
||||||
.with_processes(ProcessRefreshKind::everything())
|
|
||||||
.with_memory(MemoryRefreshKind::everything());
|
|
||||||
// only get information requested
|
|
||||||
let system = System::new_with_specifics(rk);
|
|
||||||
|
|
||||||
self.column_names()
|
|
||||||
.into_iter()
|
|
||||||
.map(|col| {
|
|
||||||
let val = self.get_column_value_with_system(col, Some(&system))?;
|
|
||||||
Ok((col.to_owned(), val))
|
|
||||||
})
|
|
||||||
.collect::<Result<Record, _>>()
|
|
||||||
.map(|record| Value::record(record, self.span()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SystemOpt<'a> {
|
|
||||||
Ptr(&'a System),
|
|
||||||
Owned(Box<System>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> SystemOpt<'a> {
|
|
||||||
fn get_system(&'a self) -> &'a System {
|
|
||||||
match self {
|
|
||||||
SystemOpt::Ptr(system) => system,
|
|
||||||
SystemOpt::Owned(system) => system,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, F: Fn() -> RefreshKind> From<(Option<&'a System>, F)> for SystemOpt<'a> {
|
|
||||||
fn from((system_opt, refresh_kind_create): (Option<&'a System>, F)) -> Self {
|
|
||||||
match system_opt {
|
|
||||||
Some(system) => SystemOpt::<'a>::Ptr(system),
|
|
||||||
None => SystemOpt::Owned(Box::new(System::new_with_specifics(refresh_kind_create()))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_thread_id() -> u64 {
|
fn get_thread_id() -> u64 {
|
||||||
|
|
|
@ -105,18 +105,6 @@ fn getcol(
|
||||||
.into_pipeline_data(ctrlc)
|
.into_pipeline_data(ctrlc)
|
||||||
.set_metadata(metadata))
|
.set_metadata(metadata))
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
Ok({
|
|
||||||
// Unfortunate casualty to LazyRecord's column_names not generating 'static strs
|
|
||||||
let cols: Vec<_> =
|
|
||||||
val.column_names().iter().map(|s| s.to_string()).collect();
|
|
||||||
|
|
||||||
cols.into_iter()
|
|
||||||
.map(move |x| Value::string(x, head))
|
|
||||||
.into_pipeline_data(ctrlc)
|
|
||||||
.set_metadata(metadata)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Value::Record { val, .. } => Ok(val
|
Value::Record { val, .. } => Ok(val
|
||||||
.into_owned()
|
.into_owned()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -533,15 +533,6 @@ fn value_should_be_printed(
|
||||||
Value::Record { val, .. } => {
|
Value::Record { val, .. } => {
|
||||||
record_matches_term(val, columns_to_search, filter_config, term, span)
|
record_matches_term(val, columns_to_search, filter_config, term, span)
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => match val.collect() {
|
|
||||||
Ok(val) => match val {
|
|
||||||
Value::Record { val, .. } => {
|
|
||||||
record_matches_term(&val, columns_to_search, filter_config, term, span)
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
Err(_) => false,
|
|
||||||
},
|
|
||||||
Value::Binary { .. } => false,
|
Value::Binary { .. } => false,
|
||||||
});
|
});
|
||||||
if invert {
|
if invert {
|
||||||
|
|
|
@ -44,12 +44,6 @@ impl Command for Items {
|
||||||
match input {
|
match input {
|
||||||
PipelineData::Empty => Ok(PipelineData::Empty),
|
PipelineData::Empty => Ok(PipelineData::Empty),
|
||||||
PipelineData::Value(value, ..) => {
|
PipelineData::Value(value, ..) => {
|
||||||
let value = if let Value::LazyRecord { val, .. } = value {
|
|
||||||
val.collect()?
|
|
||||||
} else {
|
|
||||||
value
|
|
||||||
};
|
|
||||||
|
|
||||||
let span = value.span();
|
let span = value.span();
|
||||||
match value {
|
match value {
|
||||||
Value::Record { val, .. } => {
|
Value::Record { val, .. } => {
|
||||||
|
|
|
@ -161,20 +161,6 @@ fn values(
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into_pipeline_data_with_metadata(metadata, ctrlc)),
|
.into_pipeline_data_with_metadata(metadata, ctrlc)),
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
let record = match val.collect()? {
|
|
||||||
Value::Record { val, .. } => val,
|
|
||||||
_ => Err(ShellError::NushellFailedSpanned {
|
|
||||||
msg: "`LazyRecord::collect()` promises `Value::Record`".into(),
|
|
||||||
label: "Violating lazy record found here".into(),
|
|
||||||
span,
|
|
||||||
})?,
|
|
||||||
};
|
|
||||||
Ok(record
|
|
||||||
.into_owned()
|
|
||||||
.into_values()
|
|
||||||
.into_pipeline_data_with_metadata(metadata, ctrlc))
|
|
||||||
}
|
|
||||||
// Propagate errors
|
// Propagate errors
|
||||||
Value::Error { error, .. } => Err(*error),
|
Value::Error { error, .. } => Err(*error),
|
||||||
other => Err(ShellError::OnlySupportsThisInputType {
|
other => Err(ShellError::OnlySupportsThisInputType {
|
||||||
|
|
|
@ -135,10 +135,6 @@ pub fn value_to_json_value(v: &Value) -> Result<nu_json::Value, ShellError> {
|
||||||
}
|
}
|
||||||
nu_json::Value::Object(m)
|
nu_json::Value::Object(m)
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
let collected = val.collect()?;
|
|
||||||
value_to_json_value(&collected)?
|
|
||||||
}
|
|
||||||
Value::Custom { val, .. } => {
|
Value::Custom { val, .. } => {
|
||||||
let collected = val.to_base_value(span)?;
|
let collected = val.to_base_value(span)?;
|
||||||
value_to_json_value(&collected)?
|
value_to_json_value(&collected)?
|
||||||
|
|
|
@ -246,9 +246,6 @@ pub(crate) fn write_value(
|
||||||
Value::Custom { val, .. } => {
|
Value::Custom { val, .. } => {
|
||||||
write_value(out, &val.to_base_value(span)?, depth)?;
|
write_value(out, &val.to_base_value(span)?, depth)?;
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
write_value(out, &val.collect()?, depth)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,10 +130,6 @@ fn local_into_string(value: Value, separator: &str, config: &Config) -> String {
|
||||||
.map(|(x, y)| format!("{}: {}", x, local_into_string(y, ", ", config)))
|
.map(|(x, y)| format!("{}: {}", x, local_into_string(y, ", ", config)))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(separator),
|
.join(separator),
|
||||||
Value::LazyRecord { val, .. } => match val.collect() {
|
|
||||||
Ok(val) => local_into_string(val, separator, config),
|
|
||||||
Err(error) => format!("{error:?}"),
|
|
||||||
},
|
|
||||||
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
||||||
Value::Nothing { .. } => String::new(),
|
Value::Nothing { .. } => String::new(),
|
||||||
Value::Error { error, .. } => format!("{error:?}"),
|
Value::Error { error, .. } => format!("{error:?}"),
|
||||||
|
|
|
@ -62,10 +62,6 @@ fn helper(engine_state: &EngineState, v: &Value) -> Result<toml::Value, ShellErr
|
||||||
}
|
}
|
||||||
toml::Value::Table(m)
|
toml::Value::Table(m)
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
let collected = val.collect()?;
|
|
||||||
helper(engine_state, &collected)?
|
|
||||||
}
|
|
||||||
Value::List { vals, .. } => toml::Value::Array(toml_list(engine_state, vals)?),
|
Value::List { vals, .. } => toml::Value::Array(toml_list(engine_state, vals)?),
|
||||||
Value::Closure { .. } => {
|
Value::Closure { .. } => {
|
||||||
let code = engine_state.get_span_contents(span);
|
let code = engine_state.get_span_contents(span);
|
||||||
|
|
|
@ -62,10 +62,6 @@ pub fn value_to_yaml_value(v: &Value) -> Result<serde_yaml::Value, ShellError> {
|
||||||
}
|
}
|
||||||
serde_yaml::Value::Mapping(m)
|
serde_yaml::Value::Mapping(m)
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
let collected = val.collect()?;
|
|
||||||
value_to_yaml_value(&collected)?
|
|
||||||
}
|
|
||||||
Value::List { vals, .. } => {
|
Value::List { vals, .. } => {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::LazyRecord;
|
|
||||||
use std::time::{Duration, UNIX_EPOCH};
|
use std::time::{Duration, UNIX_EPOCH};
|
||||||
use sysinfo::{
|
use sysinfo::{
|
||||||
Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL,
|
Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL,
|
||||||
|
@ -32,10 +31,7 @@ impl Command for Sys {
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let span = call.span();
|
Ok(all_columns(call.head).into_pipeline_data())
|
||||||
let ret = Value::lazy_record(Box::new(SysResult { span }), span);
|
|
||||||
|
|
||||||
Ok(ret.into_pipeline_data())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -64,36 +60,18 @@ pub struct SysResult {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LazyRecord<'_> for SysResult {
|
fn all_columns(span: Span) -> Value {
|
||||||
fn column_names(&self) -> Vec<&'static str> {
|
Value::record(
|
||||||
vec!["host", "cpu", "disks", "mem", "temp", "net"]
|
record! {
|
||||||
}
|
"host" => host(span),
|
||||||
|
"cpu" => cpu(span),
|
||||||
fn get_column_value(&self, column: &str) -> Result<Value, ShellError> {
|
"disks" => disks(span),
|
||||||
let span = self.span;
|
"mem" => mem(span),
|
||||||
|
"temp" => temp(span),
|
||||||
match column {
|
"net" => net(span),
|
||||||
"host" => Ok(host(span)),
|
},
|
||||||
"cpu" => Ok(cpu(span)),
|
|
||||||
"disks" => Ok(disks(span)),
|
|
||||||
"mem" => Ok(mem(span)),
|
|
||||||
"temp" => Ok(temp(span)),
|
|
||||||
"net" => Ok(net(span)),
|
|
||||||
_ => Err(ShellError::LazyRecordAccessFailed {
|
|
||||||
message: format!("Could not find column '{column}'"),
|
|
||||||
column_name: column.to_string(),
|
|
||||||
span,
|
span,
|
||||||
}),
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn span(&self) -> Span {
|
|
||||||
self.span
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone_value(&self, span: Span) -> Value {
|
|
||||||
Value::lazy_record(Box::new((*self).clone()), span)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trim_cstyle_null(s: String) -> String {
|
pub fn trim_cstyle_null(s: String) -> String {
|
||||||
|
|
|
@ -394,10 +394,6 @@ fn handle_table_command(
|
||||||
input.data = PipelineData::Empty;
|
input.data = PipelineData::Empty;
|
||||||
handle_record(input, cfg, val.into_owned())
|
handle_record(input, cfg, val.into_owned())
|
||||||
}
|
}
|
||||||
PipelineData::Value(Value::LazyRecord { val, .. }, ..) => {
|
|
||||||
input.data = val.collect()?.into_pipeline_data();
|
|
||||||
handle_table_command(input, cfg)
|
|
||||||
}
|
|
||||||
PipelineData::Value(Value::Error { error, .. }, ..) => {
|
PipelineData::Value(Value::Error { error, .. }, ..) => {
|
||||||
// Propagate this error outward, so that it goes to stderr
|
// Propagate this error outward, so that it goes to stderr
|
||||||
// instead of stdout.
|
// instead of stdout.
|
||||||
|
|
|
@ -98,21 +98,6 @@ fn insert_uses_enumerate_index() {
|
||||||
assert_eq!(actual.out, "[[index, a, b]; [0, 7, 8], [1, 6, 8]]");
|
assert_eq!(actual.out, "[[index, a, b]; [0, 7, 8], [1, 6, 8]]");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn insert_support_lazy_record() {
|
|
||||||
let actual =
|
|
||||||
nu!(r#"let x = (lazy make -c ["h"] -g {|a| $a | str upcase}); $x | insert a 10 | get a"#);
|
|
||||||
assert_eq!(actual.out, "10");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lazy_record_test_values() {
|
|
||||||
let actual = nu!(
|
|
||||||
r#"lazy make --columns ["haskell", "futures", "nushell"] --get-value { |lazything| $lazything + "!" } | values | length"#
|
|
||||||
);
|
|
||||||
assert_eq!(actual.out, "3");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deep_cell_path_creates_all_nested_records() {
|
fn deep_cell_path_creates_all_nested_records() {
|
||||||
let actual = nu!("{a: {}} | insert a.b.c 0 | get a.b.c");
|
let actual = nu!("{a: {}} | insert a.b.c 0 | get a.b.c");
|
||||||
|
|
|
@ -103,13 +103,6 @@ fn update_uses_enumerate_index() {
|
||||||
assert_eq!(actual.out, "[[index, a]; [0, 8], [1, 8]]");
|
assert_eq!(actual.out, "[[index, a]; [0, 8], [1, 8]]");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn update_support_lazy_record() {
|
|
||||||
let actual =
|
|
||||||
nu!(r#"let x = (lazy make -c ["h"] -g {|a| $a | str upcase}); $x | update h 10 | get h"#);
|
|
||||||
assert_eq!(actual.out, "10");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_replacement_closure() {
|
fn list_replacement_closure() {
|
||||||
let actual = nu!("[1, 2] | update 1 {|i| $i + 1 } | to nuon");
|
let actual = nu!("[1, 2] | update 1 {|i| $i + 1 } | to nuon");
|
||||||
|
|
|
@ -112,17 +112,6 @@ fn upsert_past_end_of_list_stream() {
|
||||||
.contains("can't insert at index (the next available index is 3)"));
|
.contains("can't insert at index (the next available index is 3)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn upsert_support_lazy_record() {
|
|
||||||
let actual =
|
|
||||||
nu!(r#"let x = (lazy make -c ["h"] -g {|a| $a | str upcase}); $x | upsert h 10 | get h"#);
|
|
||||||
assert_eq!(actual.out, "10");
|
|
||||||
|
|
||||||
let actual =
|
|
||||||
nu!(r#"let x = (lazy make -c ["h"] -g {|a| $a | str upcase}); $x | upsert aa 10 | get aa"#);
|
|
||||||
assert_eq!(actual.out, "10");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deep_cell_path_creates_all_nested_records() {
|
fn deep_cell_path_creates_all_nested_records() {
|
||||||
let actual = nu!("{a: {}} | upsert a.b.c 0 | get a.b.c");
|
let actual = nu!("{a: {}} | upsert a.b.c 0 | get a.b.c");
|
||||||
|
|
|
@ -112,10 +112,6 @@ pub fn collect_input(value: Value) -> Result<(Vec<String>, Vec<Vec<Value>>)> {
|
||||||
|
|
||||||
Ok((vec![String::from("")], lines))
|
Ok((vec![String::from("")], lines))
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
let materialized = val.collect()?;
|
|
||||||
collect_input(materialized)
|
|
||||||
}
|
|
||||||
Value::Nothing { .. } => Ok((vec![], vec![])),
|
Value::Nothing { .. } => Ok((vec![], vec![])),
|
||||||
Value::Custom { val, .. } => {
|
Value::Custom { val, .. } => {
|
||||||
let materialized = val.to_base_value(span)?;
|
let materialized = val.to_base_value(span)?;
|
||||||
|
|
|
@ -2,8 +2,6 @@ use nu_protocol::{CustomValue, IntoSpanned, ShellError, Spanned, Value};
|
||||||
|
|
||||||
/// Do something with all [`CustomValue`]s recursively within a `Value`. This is not limited to
|
/// Do something with all [`CustomValue`]s recursively within a `Value`. This is not limited to
|
||||||
/// plugin custom values.
|
/// plugin custom values.
|
||||||
///
|
|
||||||
/// `LazyRecord`s will be collected to plain values for completeness.
|
|
||||||
pub fn with_custom_values_in<E>(
|
pub fn with_custom_values_in<E>(
|
||||||
value: &mut Value,
|
value: &mut Value,
|
||||||
mut f: impl FnMut(Spanned<&mut Box<dyn CustomValue>>) -> Result<(), E>,
|
mut f: impl FnMut(Spanned<&mut Box<dyn CustomValue>>) -> Result<(), E>,
|
||||||
|
@ -18,13 +16,6 @@ where
|
||||||
// Operate on a CustomValue.
|
// Operate on a CustomValue.
|
||||||
f(val.into_spanned(span))
|
f(val.into_spanned(span))
|
||||||
}
|
}
|
||||||
// LazyRecord would be a problem for us, since it could return something else the
|
|
||||||
// next time, and we have to collect it anyway to serialize it. Collect it in place,
|
|
||||||
// and then use the result
|
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
*value = val.collect()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -33,31 +24,7 @@ where
|
||||||
#[test]
|
#[test]
|
||||||
fn find_custom_values() {
|
fn find_custom_values() {
|
||||||
use nu_plugin_protocol::test_util::test_plugin_custom_value;
|
use nu_plugin_protocol::test_util::test_plugin_custom_value;
|
||||||
use nu_protocol::{engine::Closure, record, LazyRecord, Span};
|
use nu_protocol::{engine::Closure, record};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct Lazy;
|
|
||||||
impl<'a> LazyRecord<'a> for Lazy {
|
|
||||||
fn column_names(&'a self) -> Vec<&'a str> {
|
|
||||||
vec!["custom", "plain"]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_column_value(&self, column: &str) -> Result<Value, ShellError> {
|
|
||||||
Ok(match column {
|
|
||||||
"custom" => Value::test_custom_value(Box::new(test_plugin_custom_value())),
|
|
||||||
"plain" => Value::test_int(42),
|
|
||||||
_ => unimplemented!(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn span(&self) -> Span {
|
|
||||||
Span::test_data()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone_value(&self, span: Span) -> Value {
|
|
||||||
Value::lazy_record(Box::new(self.clone()), span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cv = Value::test_custom_value(Box::new(test_plugin_custom_value()));
|
let mut cv = Value::test_custom_value(Box::new(test_plugin_custom_value()));
|
||||||
|
|
||||||
|
@ -73,7 +40,6 @@ fn find_custom_values() {
|
||||||
captures: vec![(0, cv.clone()), (1, Value::test_string("foo"))]
|
captures: vec![(0, cv.clone()), (1, Value::test_string("foo"))]
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
"lazy" => Value::test_lazy_record(Box::new(Lazy)),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Do with_custom_values_in, and count the number of custom values found
|
// Do with_custom_values_in, and count the number of custom values found
|
||||||
|
@ -83,7 +49,7 @@ fn find_custom_values() {
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.expect("error");
|
.expect("error");
|
||||||
assert_eq!(4, found, "found in value");
|
assert_eq!(3, found, "found in value");
|
||||||
|
|
||||||
// Try it on bare custom value too
|
// Try it on bare custom value too
|
||||||
found = 0;
|
found = 0;
|
||||||
|
|
|
@ -179,11 +179,6 @@ impl PluginCustomValue {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Collect LazyRecord before proceeding
|
|
||||||
Value::LazyRecord { ref val, .. } => {
|
|
||||||
*value = val.collect()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -205,11 +200,6 @@ impl PluginCustomValue {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Collect LazyRecord before proceeding
|
|
||||||
Value::LazyRecord { ref val, .. } => {
|
|
||||||
*value = val.collect()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -224,11 +214,6 @@ impl PluginCustomValue {
|
||||||
*value = val.to_base_value(span)?;
|
*value = val.to_base_value(span)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// Collect LazyRecord before proceeding
|
|
||||||
Value::LazyRecord { ref val, .. } => {
|
|
||||||
*value = val.collect()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -344,9 +344,6 @@ impl PluginTest {
|
||||||
// All equal, and same length
|
// All equal, and same length
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
// Must collect lazy records to compare.
|
|
||||||
(Value::LazyRecord { val: a_val, .. }, _) => self.value_eq(&a_val.collect()?, b),
|
|
||||||
(_, Value::LazyRecord { val: b_val, .. }) => self.value_eq(a, &b_val.collect()?),
|
|
||||||
// Fall back to regular eq.
|
// Fall back to regular eq.
|
||||||
_ => Ok(a == b),
|
_ => Ok(a == b),
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,11 +381,6 @@ pub(crate) fn render_examples(
|
||||||
plugin.custom_value_to_base_value(engine, val.into_spanned(span))?;
|
plugin.custom_value_to_base_value(engine, val.into_spanned(span))?;
|
||||||
Ok::<_, ShellError>(())
|
Ok::<_, ShellError>(())
|
||||||
}
|
}
|
||||||
// Collect LazyRecord before proceeding
|
|
||||||
Value::LazyRecord { ref val, .. } => {
|
|
||||||
*value = val.collect()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
|
@ -1178,16 +1178,6 @@ pub enum ShellError {
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// An attempt to access a record column failed.
|
|
||||||
#[error("Access failure: {message}")]
|
|
||||||
#[diagnostic(code(nu::shell::lazy_record_access_failed))]
|
|
||||||
LazyRecordAccessFailed {
|
|
||||||
message: String,
|
|
||||||
column_name: String,
|
|
||||||
#[label("Could not access '{column_name}' on this record")]
|
|
||||||
span: Span,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Operation interrupted by user
|
/// Operation interrupted by user
|
||||||
#[error("Operation interrupted by user")]
|
#[error("Operation interrupted by user")]
|
||||||
InterruptedByUser {
|
InterruptedByUser {
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
use crate::{Record, ShellError, Span, Value};
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
// Trait definition for a lazy record (where columns are evaluated on-demand)
|
|
||||||
// typetag is needed to make this implement Serialize+Deserialize... even though we should never actually serialize a LazyRecord.
|
|
||||||
// To serialize a LazyRecord, collect it into a Value::Record with collect() first.
|
|
||||||
pub trait LazyRecord<'a>: fmt::Debug + Send + Sync {
|
|
||||||
// All column names
|
|
||||||
fn column_names(&'a self) -> Vec<&'a str>;
|
|
||||||
|
|
||||||
// Get 1 specific column value
|
|
||||||
fn get_column_value(&self, column: &str) -> Result<Value, ShellError>;
|
|
||||||
|
|
||||||
fn span(&self) -> Span;
|
|
||||||
|
|
||||||
// Convert the lazy record into a regular Value::Record by collecting all its columns
|
|
||||||
fn collect(&'a self) -> Result<Value, ShellError> {
|
|
||||||
self.column_names()
|
|
||||||
.into_iter()
|
|
||||||
.map(|col| {
|
|
||||||
let val = self.get_column_value(col)?;
|
|
||||||
Ok((col.to_owned(), val))
|
|
||||||
})
|
|
||||||
.collect::<Result<Record, _>>()
|
|
||||||
.map(|record| Value::record(record, self.span()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone_value(&self, span: Span) -> Value;
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ mod filesize;
|
||||||
mod from;
|
mod from;
|
||||||
mod from_value;
|
mod from_value;
|
||||||
mod glob;
|
mod glob;
|
||||||
mod lazy_record;
|
|
||||||
mod range;
|
mod range;
|
||||||
|
|
||||||
pub mod record;
|
pub mod record;
|
||||||
|
@ -13,7 +12,6 @@ pub use duration::*;
|
||||||
pub use filesize::*;
|
pub use filesize::*;
|
||||||
pub use from_value::FromValue;
|
pub use from_value::FromValue;
|
||||||
pub use glob::*;
|
pub use glob::*;
|
||||||
pub use lazy_record::LazyRecord;
|
|
||||||
pub use range::{FloatRange, IntRange, Range};
|
pub use range::{FloatRange, IntRange, Range};
|
||||||
pub use record::Record;
|
pub use record::Record;
|
||||||
|
|
||||||
|
@ -164,13 +162,6 @@ pub enum Value {
|
||||||
#[serde(rename = "span")]
|
#[serde(rename = "span")]
|
||||||
internal_span: Span,
|
internal_span: Span,
|
||||||
},
|
},
|
||||||
#[serde(skip)]
|
|
||||||
LazyRecord {
|
|
||||||
val: Box<dyn for<'a> LazyRecord<'a>>,
|
|
||||||
// note: spans are being refactored out of Value
|
|
||||||
// please use .span() instead of matching this span value
|
|
||||||
internal_span: Span,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Value {
|
impl Clone for Value {
|
||||||
|
@ -212,7 +203,6 @@ impl Clone for Value {
|
||||||
val: val.clone(),
|
val: val.clone(),
|
||||||
internal_span: *internal_span,
|
internal_span: *internal_span,
|
||||||
},
|
},
|
||||||
Value::LazyRecord { val, internal_span } => val.clone_value(*internal_span),
|
|
||||||
Value::List {
|
Value::List {
|
||||||
vals,
|
vals,
|
||||||
internal_span,
|
internal_span,
|
||||||
|
@ -672,24 +662,6 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the inner [`LazyRecord`] trait object or an error if this `Value` is not a lazy record
|
|
||||||
pub fn as_lazy_record(&self) -> Result<&dyn for<'a> LazyRecord<'a>, ShellError> {
|
|
||||||
if let Value::LazyRecord { val, .. } = self {
|
|
||||||
Ok(val.as_ref())
|
|
||||||
} else {
|
|
||||||
self.cant_convert_to("lazy record")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unwraps the inner [`LazyRecord`] trait object or returns an error if this `Value` is not a lazy record
|
|
||||||
pub fn into_lazy_record(self) -> Result<Box<dyn for<'a> LazyRecord<'a>>, ShellError> {
|
|
||||||
if let Value::LazyRecord { val, .. } = self {
|
|
||||||
Ok(val)
|
|
||||||
} else {
|
|
||||||
self.cant_convert_to("lazy record")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the span for the current value
|
/// Get the span for the current value
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
|
@ -709,7 +681,6 @@ impl Value {
|
||||||
| Value::Binary { internal_span, .. }
|
| Value::Binary { internal_span, .. }
|
||||||
| Value::CellPath { internal_span, .. }
|
| Value::CellPath { internal_span, .. }
|
||||||
| Value::Custom { internal_span, .. }
|
| Value::Custom { internal_span, .. }
|
||||||
| Value::LazyRecord { internal_span, .. }
|
|
||||||
| Value::Error { internal_span, .. } => *internal_span,
|
| Value::Error { internal_span, .. } => *internal_span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -727,7 +698,6 @@ impl Value {
|
||||||
| Value::String { internal_span, .. }
|
| Value::String { internal_span, .. }
|
||||||
| Value::Glob { internal_span, .. }
|
| Value::Glob { internal_span, .. }
|
||||||
| Value::Record { internal_span, .. }
|
| Value::Record { internal_span, .. }
|
||||||
| Value::LazyRecord { internal_span, .. }
|
|
||||||
| Value::List { internal_span, .. }
|
| Value::List { internal_span, .. }
|
||||||
| Value::Closure { internal_span, .. }
|
| Value::Closure { internal_span, .. }
|
||||||
| Value::Nothing { internal_span, .. }
|
| Value::Nothing { internal_span, .. }
|
||||||
|
@ -784,10 +754,6 @@ impl Value {
|
||||||
None => Type::List(Box::new(Type::Any)),
|
None => Type::List(Box::new(Type::Any)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => match val.collect() {
|
|
||||||
Ok(val) => val.get_type(),
|
|
||||||
Err(..) => Type::Error,
|
|
||||||
},
|
|
||||||
Value::Nothing { .. } => Type::Nothing,
|
Value::Nothing { .. } => Type::Nothing,
|
||||||
Value::Closure { .. } => Type::Closure,
|
Value::Closure { .. } => Type::Closure,
|
||||||
Value::Error { .. } => Type::Error,
|
Value::Error { .. } => Type::Error,
|
||||||
|
@ -893,10 +859,6 @@ impl Value {
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(separator)
|
.join(separator)
|
||||||
),
|
),
|
||||||
Value::LazyRecord { val, .. } => val
|
|
||||||
.collect()
|
|
||||||
.unwrap_or_else(|err| Value::error(err, span))
|
|
||||||
.to_expanded_string(separator, config),
|
|
||||||
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
||||||
Value::Nothing { .. } => String::new(),
|
Value::Nothing { .. } => String::new(),
|
||||||
Value::Error { error, .. } => format!("{error:?}"),
|
Value::Error { error, .. } => format!("{error:?}"),
|
||||||
|
@ -919,7 +881,6 @@ impl Value {
|
||||||
/// - "[list {n} items]"
|
/// - "[list {n} items]"
|
||||||
/// - "[record {n} fields]"
|
/// - "[record {n} fields]"
|
||||||
pub fn to_abbreviated_string(&self, config: &Config) -> String {
|
pub fn to_abbreviated_string(&self, config: &Config) -> String {
|
||||||
let span = self.span();
|
|
||||||
match self {
|
match self {
|
||||||
Value::Date { val, .. } => match &config.datetime_table_format {
|
Value::Date { val, .. } => match &config.datetime_table_format {
|
||||||
Some(format) => self.format_datetime(val, format),
|
Some(format) => self.format_datetime(val, format),
|
||||||
|
@ -945,10 +906,6 @@ impl Value {
|
||||||
val.len(),
|
val.len(),
|
||||||
if val.len() == 1 { "" } else { "s" }
|
if val.len() == 1 { "" } else { "s" }
|
||||||
),
|
),
|
||||||
Value::LazyRecord { val, .. } => val
|
|
||||||
.collect()
|
|
||||||
.unwrap_or_else(|err| Value::error(err, span))
|
|
||||||
.to_abbreviated_string(config),
|
|
||||||
val => val.to_expanded_string(", ", config),
|
val => val.to_expanded_string(", ", config),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1087,7 +1044,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
// Records (and tables) are the only built-in which support column names,
|
// Records (and tables) are the only built-in which support column names,
|
||||||
// so only use this message for them.
|
// so only use this message for them.
|
||||||
Value::Record { .. } | Value::LazyRecord { .. } => {
|
Value::Record { .. } => {
|
||||||
return Err(ShellError::TypeMismatch {
|
return Err(ShellError::TypeMismatch {
|
||||||
err_message:"Can't access record values with a row index. Try specifying a column name instead".into(),
|
err_message:"Can't access record values with a row index. Try specifying a column name instead".into(),
|
||||||
span: *origin_span,
|
span: *origin_span,
|
||||||
|
@ -1137,32 +1094,6 @@ impl Value {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
let columns = val.column_names();
|
|
||||||
|
|
||||||
if let Some(col) = columns.iter().rev().find(|&col| {
|
|
||||||
if insensitive {
|
|
||||||
col.eq_ignore_case(column_name)
|
|
||||||
} else {
|
|
||||||
col == column_name
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
current = val.get_column_value(col)?;
|
|
||||||
} else if *optional {
|
|
||||||
return Ok(Value::nothing(*origin_span)); // short-circuit
|
|
||||||
} else if let Some(suggestion) = did_you_mean(&columns, column_name) {
|
|
||||||
return Err(ShellError::DidYouMean {
|
|
||||||
suggestion,
|
|
||||||
span: *origin_span,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::CantFindColumn {
|
|
||||||
col_name: column_name.clone(),
|
|
||||||
span: *origin_span,
|
|
||||||
src_span: span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// String access of Lists always means Table access.
|
// String access of Lists always means Table access.
|
||||||
// Create a List which contains each matching value for contained
|
// Create a List which contains each matching value for contained
|
||||||
// records in the source list.
|
// records in the source list.
|
||||||
|
@ -1327,11 +1258,6 @@ impl Value {
|
||||||
record.to_mut().push(col_name, new_col);
|
record.to_mut().push(col_name, new_col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
// convert to Record first.
|
|
||||||
*self = val.collect()?;
|
|
||||||
self.upsert_data_at_cell_path(cell_path, new_val)?;
|
|
||||||
}
|
|
||||||
Value::Error { error, .. } => return Err(*error.clone()),
|
Value::Error { error, .. } => return Err(*error.clone()),
|
||||||
v => {
|
v => {
|
||||||
return Err(ShellError::CantFindColumn {
|
return Err(ShellError::CantFindColumn {
|
||||||
|
@ -1443,11 +1369,6 @@ impl Value {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
// convert to Record first.
|
|
||||||
*self = val.collect()?;
|
|
||||||
self.update_data_at_cell_path(cell_path, new_val)?;
|
|
||||||
}
|
|
||||||
Value::Error { error, .. } => return Err(*error.clone()),
|
Value::Error { error, .. } => return Err(*error.clone()),
|
||||||
v => {
|
v => {
|
||||||
return Err(ShellError::CantFindColumn {
|
return Err(ShellError::CantFindColumn {
|
||||||
|
@ -1532,11 +1453,6 @@ impl Value {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
// convert to Record first.
|
|
||||||
*self = val.collect()?;
|
|
||||||
self.remove_data_at_cell_path(cell_path)
|
|
||||||
}
|
|
||||||
v => Err(ShellError::CantFindColumn {
|
v => Err(ShellError::CantFindColumn {
|
||||||
col_name: col_name.clone(),
|
col_name: col_name.clone(),
|
||||||
span: *span,
|
span: *span,
|
||||||
|
@ -1616,11 +1532,6 @@ impl Value {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
// convert to Record first.
|
|
||||||
*self = val.collect()?;
|
|
||||||
self.remove_data_at_cell_path(cell_path)
|
|
||||||
}
|
|
||||||
v => Err(ShellError::CantFindColumn {
|
v => Err(ShellError::CantFindColumn {
|
||||||
col_name: col_name.clone(),
|
col_name: col_name.clone(),
|
||||||
span: *span,
|
span: *span,
|
||||||
|
@ -1739,11 +1650,6 @@ impl Value {
|
||||||
record.to_mut().push(col_name, new_col);
|
record.to_mut().push(col_name, new_col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
// convert to Record first.
|
|
||||||
*self = val.collect()?;
|
|
||||||
self.insert_data_at_cell_path(cell_path, new_val, v_span)?;
|
|
||||||
}
|
|
||||||
other => {
|
other => {
|
||||||
return Err(ShellError::UnsupportedInput {
|
return Err(ShellError::UnsupportedInput {
|
||||||
msg: "table or record".into(),
|
msg: "table or record".into(),
|
||||||
|
@ -1797,8 +1703,6 @@ impl Value {
|
||||||
///
|
///
|
||||||
/// If the closure returns `Err`, the traversal will stop.
|
/// If the closure returns `Err`, the traversal will stop.
|
||||||
///
|
///
|
||||||
/// If collecting lazy records to check them as well is desirable, make sure to do it in your
|
|
||||||
/// closure. The traversal continues on whatever modifications you make during the closure.
|
|
||||||
/// Captures of closure values are currently visited, as they are values owned by the closure.
|
/// Captures of closure values are currently visited, as they are values owned by the closure.
|
||||||
pub fn recurse_mut<E>(
|
pub fn recurse_mut<E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1837,7 +1741,7 @@ impl Value {
|
||||||
| Value::Binary { .. }
|
| Value::Binary { .. }
|
||||||
| Value::CellPath { .. } => Ok(()),
|
| Value::CellPath { .. } => Ok(()),
|
||||||
// These could potentially contain values, but we expect the closure to handle them
|
// These could potentially contain values, but we expect the closure to handle them
|
||||||
Value::LazyRecord { .. } | Value::Custom { .. } => Ok(()),
|
Value::Custom { .. } => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1998,13 +1902,6 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lazy_record(val: Box<dyn for<'a> LazyRecord<'a>>, span: Span) -> Value {
|
|
||||||
Value::LazyRecord {
|
|
||||||
val,
|
|
||||||
internal_span: span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
|
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
|
||||||
/// when used in errors.
|
/// when used in errors.
|
||||||
pub fn test_bool(val: bool) -> Value {
|
pub fn test_bool(val: bool) -> Value {
|
||||||
|
@ -2101,17 +1998,11 @@ impl Value {
|
||||||
Value::custom(val, Span::test_data())
|
Value::custom(val, Span::test_data())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
|
|
||||||
/// when used in errors.
|
|
||||||
pub fn test_lazy_record(val: Box<dyn for<'a> LazyRecord<'a>>) -> Value {
|
|
||||||
Value::lazy_record(val, Span::test_data())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Note: Only use this for test data, *not* live data,
|
/// Note: Only use this for test data, *not* live data,
|
||||||
/// as it will point into unknown source when used in errors.
|
/// as it will point into unknown source when used in errors.
|
||||||
///
|
///
|
||||||
/// Returns a `Vec` containing one of each value case (`Value::Int`, `Value::String`, etc.)
|
/// Returns a `Vec` containing one of each value case (`Value::Int`, `Value::String`, etc.)
|
||||||
/// except for `Value::LazyRecord` and `Value::CustomValue`.
|
/// except for `Value::CustomValue`.
|
||||||
pub fn test_values() -> Vec<Value> {
|
pub fn test_values() -> Vec<Value> {
|
||||||
vec![
|
vec![
|
||||||
Value::test_bool(false),
|
Value::test_bool(false),
|
||||||
|
@ -2127,7 +2018,6 @@ impl Value {
|
||||||
Value::test_float(0.0),
|
Value::test_float(0.0),
|
||||||
Value::test_string(String::new()),
|
Value::test_string(String::new()),
|
||||||
Value::test_record(Record::new()),
|
Value::test_record(Record::new()),
|
||||||
// Value::test_lazy_record(Box::new(todo!())),
|
|
||||||
Value::test_list(Vec::new()),
|
Value::test_list(Vec::new()),
|
||||||
Value::test_closure(Closure {
|
Value::test_closure(Closure {
|
||||||
block_id: 0,
|
block_id: 0,
|
||||||
|
@ -2181,7 +2071,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Less),
|
Value::String { .. } => Some(Ordering::Less),
|
||||||
Value::Glob { .. } => Some(Ordering::Less),
|
Value::Glob { .. } => Some(Ordering::Less),
|
||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2201,7 +2090,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Less),
|
Value::String { .. } => Some(Ordering::Less),
|
||||||
Value::Glob { .. } => Some(Ordering::Less),
|
Value::Glob { .. } => Some(Ordering::Less),
|
||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2221,7 +2109,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Less),
|
Value::String { .. } => Some(Ordering::Less),
|
||||||
Value::Glob { .. } => Some(Ordering::Less),
|
Value::Glob { .. } => Some(Ordering::Less),
|
||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2241,7 +2128,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Less),
|
Value::String { .. } => Some(Ordering::Less),
|
||||||
Value::Glob { .. } => Some(Ordering::Less),
|
Value::Glob { .. } => Some(Ordering::Less),
|
||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2261,7 +2147,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Less),
|
Value::String { .. } => Some(Ordering::Less),
|
||||||
Value::Glob { .. } => Some(Ordering::Less),
|
Value::Glob { .. } => Some(Ordering::Less),
|
||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2281,7 +2166,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Less),
|
Value::String { .. } => Some(Ordering::Less),
|
||||||
Value::Glob { .. } => Some(Ordering::Less),
|
Value::Glob { .. } => Some(Ordering::Less),
|
||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2301,7 +2185,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Less),
|
Value::String { .. } => Some(Ordering::Less),
|
||||||
Value::Glob { .. } => Some(Ordering::Less),
|
Value::Glob { .. } => Some(Ordering::Less),
|
||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2321,7 +2204,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { val: rhs, .. } => lhs.partial_cmp(rhs),
|
Value::String { val: rhs, .. } => lhs.partial_cmp(rhs),
|
||||||
Value::Glob { val: rhs, .. } => lhs.partial_cmp(rhs),
|
Value::Glob { val: rhs, .. } => lhs.partial_cmp(rhs),
|
||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2341,7 +2223,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { val: rhs, .. } => lhs.partial_cmp(rhs),
|
Value::String { val: rhs, .. } => lhs.partial_cmp(rhs),
|
||||||
Value::Glob { val: rhs, .. } => lhs.partial_cmp(rhs),
|
Value::Glob { val: rhs, .. } => lhs.partial_cmp(rhs),
|
||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2387,13 +2268,6 @@ impl PartialOrd for Value {
|
||||||
// that the shorter sequence is less than the longer one
|
// that the shorter sequence is less than the longer one
|
||||||
lhs.len().partial_cmp(&rhs.len())
|
lhs.len().partial_cmp(&rhs.len())
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
if let Ok(rhs) = val.collect() {
|
|
||||||
self.partial_cmp(&rhs)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2413,7 +2287,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Greater),
|
Value::String { .. } => Some(Ordering::Greater),
|
||||||
Value::Glob { .. } => Some(Ordering::Greater),
|
Value::Glob { .. } => Some(Ordering::Greater),
|
||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
|
||||||
Value::List { vals: rhs, .. } => lhs.partial_cmp(rhs),
|
Value::List { vals: rhs, .. } => lhs.partial_cmp(rhs),
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2433,7 +2306,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Greater),
|
Value::String { .. } => Some(Ordering::Greater),
|
||||||
Value::Glob { .. } => Some(Ordering::Greater),
|
Value::Glob { .. } => Some(Ordering::Greater),
|
||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Closure { val: rhs, .. } => lhs.block_id.partial_cmp(&rhs.block_id),
|
Value::Closure { val: rhs, .. } => lhs.block_id.partial_cmp(&rhs.block_id),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
|
@ -2453,7 +2325,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Greater),
|
Value::String { .. } => Some(Ordering::Greater),
|
||||||
Value::Glob { .. } => Some(Ordering::Greater),
|
Value::Glob { .. } => Some(Ordering::Greater),
|
||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Closure { .. } => Some(Ordering::Greater),
|
Value::Closure { .. } => Some(Ordering::Greater),
|
||||||
Value::Nothing { .. } => Some(Ordering::Equal),
|
Value::Nothing { .. } => Some(Ordering::Equal),
|
||||||
|
@ -2473,7 +2344,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Greater),
|
Value::String { .. } => Some(Ordering::Greater),
|
||||||
Value::Glob { .. } => Some(Ordering::Greater),
|
Value::Glob { .. } => Some(Ordering::Greater),
|
||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Closure { .. } => Some(Ordering::Greater),
|
Value::Closure { .. } => Some(Ordering::Greater),
|
||||||
Value::Nothing { .. } => Some(Ordering::Greater),
|
Value::Nothing { .. } => Some(Ordering::Greater),
|
||||||
|
@ -2493,7 +2363,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Greater),
|
Value::String { .. } => Some(Ordering::Greater),
|
||||||
Value::Glob { .. } => Some(Ordering::Greater),
|
Value::Glob { .. } => Some(Ordering::Greater),
|
||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Closure { .. } => Some(Ordering::Greater),
|
Value::Closure { .. } => Some(Ordering::Greater),
|
||||||
Value::Nothing { .. } => Some(Ordering::Greater),
|
Value::Nothing { .. } => Some(Ordering::Greater),
|
||||||
|
@ -2513,7 +2382,6 @@ impl PartialOrd for Value {
|
||||||
Value::String { .. } => Some(Ordering::Greater),
|
Value::String { .. } => Some(Ordering::Greater),
|
||||||
Value::Glob { .. } => Some(Ordering::Greater),
|
Value::Glob { .. } => Some(Ordering::Greater),
|
||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Closure { .. } => Some(Ordering::Greater),
|
Value::Closure { .. } => Some(Ordering::Greater),
|
||||||
Value::Nothing { .. } => Some(Ordering::Greater),
|
Value::Nothing { .. } => Some(Ordering::Greater),
|
||||||
|
@ -2523,13 +2391,6 @@ impl PartialOrd for Value {
|
||||||
Value::Custom { .. } => Some(Ordering::Less),
|
Value::Custom { .. } => Some(Ordering::Less),
|
||||||
},
|
},
|
||||||
(Value::Custom { val: lhs, .. }, rhs) => lhs.partial_cmp(rhs),
|
(Value::Custom { val: lhs, .. }, rhs) => lhs.partial_cmp(rhs),
|
||||||
(Value::LazyRecord { val, .. }, rhs) => {
|
|
||||||
if let Ok(val) = val.collect() {
|
|
||||||
val.partial_cmp(rhs)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,10 +221,6 @@ fn value_to_string(
|
||||||
collection.join(&format!(",{sep}{nl}"))
|
collection.join(&format!(",{sep}{nl}"))
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Value::LazyRecord { val, .. } => {
|
|
||||||
let collected = val.collect()?;
|
|
||||||
value_to_string(&collected, span, depth + 1, indent)
|
|
||||||
}
|
|
||||||
// All strings outside data structures are quoted because they are in 'command position'
|
// All strings outside data structures are quoted because they are in 'command position'
|
||||||
// (could be mistaken for commands by the Nu parser)
|
// (could be mistaken for commands by the Nu parser)
|
||||||
Value::String { val, .. } => Ok(escape_quote_string(val)),
|
Value::String { val, .. } => Ok(escape_quote_string(val)),
|
||||||
|
|
Loading…
Reference in a new issue