From 847646e44e4fbd70e574ca389935cf8876865d60 Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Fri, 3 May 2024 00:36:10 +0000 Subject: [PATCH] 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). --- .../src/completions/variable_completions.rs | 29 -- .../nu-cmd-lang/src/core_commands/describe.rs | 75 +---- .../src/core_commands/lazy_make.rs | 179 ----------- crates/nu-cmd-lang/src/core_commands/mod.rs | 2 - crates/nu-cmd-lang/src/default_context.rs | 1 - crates/nu-cmd-lang/src/example_support.rs | 4 - crates/nu-color-config/src/style_computer.rs | 7 +- crates/nu-command/src/debug/explain.rs | 4 - crates/nu-command/src/debug/info.rs | 301 ++++++------------ crates/nu-command/src/filters/columns.rs | 12 - crates/nu-command/src/filters/find.rs | 9 - crates/nu-command/src/filters/items.rs | 6 - crates/nu-command/src/filters/values.rs | 14 - crates/nu-command/src/formats/to/json.rs | 4 - crates/nu-command/src/formats/to/msgpack.rs | 3 - crates/nu-command/src/formats/to/text.rs | 4 - crates/nu-command/src/formats/to/toml.rs | 4 - crates/nu-command/src/formats/to/yaml.rs | 4 - crates/nu-command/src/system/sys.rs | 48 +-- crates/nu-command/src/viewers/table.rs | 4 - crates/nu-command/tests/commands/insert.rs | 15 - crates/nu-command/tests/commands/update.rs | 7 - crates/nu-command/tests/commands/upsert.rs | 11 - crates/nu-explore/src/nu_common/value.rs | 4 - .../src/util/with_custom_values_in.rs | 38 +-- .../src/plugin_custom_value/mod.rs | 15 - .../nu-plugin-test-support/src/plugin_test.rs | 3 - crates/nu-plugin/src/plugin/command.rs | 5 - crates/nu-protocol/src/errors/shell_error.rs | 10 - crates/nu-protocol/src/value/lazy_record.rs | 29 -- crates/nu-protocol/src/value/mod.rs | 145 +-------- crates/nuon/src/to.rs | 4 - 32 files changed, 133 insertions(+), 867 deletions(-) delete mode 100644 crates/nu-cmd-lang/src/core_commands/lazy_make.rs delete mode 100644 crates/nu-protocol/src/value/lazy_record.rs diff --git a/crates/nu-cli/src/completions/variable_completions.rs b/crates/nu-cli/src/completions/variable_completions.rs index c8cadc0d0b..b869e9f972 100644 --- a/crates/nu-cli/src/completions/variable_completions.rs +++ b/crates/nu-cli/src/completions/variable_completions.rs @@ -267,24 +267,6 @@ fn nested_suggestions( 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, .. } => { for column_name in get_columns(vals.as_slice()) { output.push(SemanticSuggestion { @@ -321,17 +303,6 @@ fn recursive_value(val: &Value, sublevels: &[Vec]) -> Result { 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, .. } => { for col in get_columns(vals.as_slice()) { if col.as_bytes() == *sublevel { diff --git a/crates/nu-cmd-lang/src/core_commands/describe.rs b/crates/nu-cmd-lang/src/core_commands/describe.rs index 58384d837b..48b52036e1 100644 --- a/crates/nu-cmd-lang/src/core_commands/describe.rs +++ b/crates/nu-cmd-lang/src/core_commands/describe.rs @@ -26,7 +26,6 @@ impl Command for Describe { "show detailed information about the value", Some('d'), ) - .switch("collect-lazyrecords", "collect lazy records", Some('l')) .category(Category::Core) } @@ -44,21 +43,7 @@ impl Command for Describe { let options = Options { no_collect: call.has_flag(engine_state, stack, "no-collect")?, 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) } @@ -71,7 +56,6 @@ impl Command for Describe { let options = Options { no_collect: call.has_flag_const(working_set, "no-collect")?, detailed: call.has_flag_const(working_set, "detailed")?, - collect_lazyrecords: call.has_flag_const(working_set, "collect-lazyrecords")?, }; 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", result: Some(Value::test_record(record!( "type" => Value::test_string("record"), - "lazy" => Value::test_bool(false), "columns" => Value::test_record(record!( "shell" => Value::test_string("string"), "uwu" => Value::test_string("bool"), "features" => Value::test_record(record!( "type" => Value::test_string("record"), - "lazy" => Value::test_bool(false), "columns" => Value::test_record(record!( "bugs" => Value::test_string("bool"), "multiplatform" => Value::test_string("bool"), @@ -168,7 +150,6 @@ impl Command for Describe { struct Options { no_collect: bool, detailed: bool, - collect_lazyrecords: bool, } fn run( @@ -243,7 +224,7 @@ fn run( if options.no_collect { Value::string("any", head) } 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), @@ -264,7 +245,7 @@ fn run( if !options.detailed { Value::string(value.get_type().to_string(), head) } else { - describe_value(value, head, engine_state, options)? + describe_value(value, head, engine_state) } } }; @@ -288,9 +269,8 @@ fn describe_value( value: Value, head: nu_protocol::Span, engine_state: Option<&EngineState>, - options: Options, -) -> Result { - Ok(match value { +) -> Value { + match value { Value::Custom { val, .. } => Value::record( record!( "type" => Value::string("custom", head), @@ -320,14 +300,12 @@ fn describe_value( std::mem::take(v), head, engine_state, - options, - )?); + )); } Value::record( record!( "type" => Value::string("record", head), - "lazy" => Value::bool(false, head), "columns" => Value::record(val, head), ), head, @@ -338,11 +316,9 @@ fn describe_value( "type" => Value::string("list", head), "length" => Value::int(vals.len() as i64, head), "values" => Value::list(vals.into_iter().map(|v| - Ok(compact_primitive_description( - describe_value(v, head, engine_state, options)? - )) + compact_primitive_description(describe_value(v, head, engine_state)) ) - .collect::, ShellError>>()?, head), + .collect(), head), ), head, ), @@ -394,42 +370,7 @@ fn describe_value( ), 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>, head: nu_protocol::Span) -> Value { diff --git a/crates/nu-cmd-lang/src/core_commands/lazy_make.rs b/crates/nu-cmd-lang/src/core_commands/lazy_make.rs deleted file mode 100644 index 7c90a04b78..0000000000 --- a/crates/nu-cmd-lang/src/core_commands/lazy_make.rs +++ /dev/null @@ -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 { - 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> = 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 { - 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>, - columns: Vec, - 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 { - 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::( - &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) - } -} diff --git a/crates/nu-cmd-lang/src/core_commands/mod.rs b/crates/nu-cmd-lang/src/core_commands/mod.rs index 87e42783e1..2b865641e8 100644 --- a/crates/nu-cmd-lang/src/core_commands/mod.rs +++ b/crates/nu-cmd-lang/src/core_commands/mod.rs @@ -21,7 +21,6 @@ mod hide; mod hide_env; mod if_; mod ignore; -mod lazy_make; mod let_; mod loop_; mod match_; @@ -58,7 +57,6 @@ pub use hide::Hide; pub use hide_env::HideEnv; pub use if_::If; pub use ignore::Ignore; -pub use lazy_make::LazyMake; pub use let_::Let; pub use loop_::Loop; pub use match_::Match; diff --git a/crates/nu-cmd-lang/src/default_context.rs b/crates/nu-cmd-lang/src/default_context.rs index 2e1681af74..43fa0ddbf5 100644 --- a/crates/nu-cmd-lang/src/default_context.rs +++ b/crates/nu-cmd-lang/src/default_context.rs @@ -43,7 +43,6 @@ pub fn create_default_context() -> EngineState { OverlayList, OverlayNew, OverlayHide, - LazyMake, Let, Loop, Match, diff --git a/crates/nu-cmd-lang/src/example_support.rs b/crates/nu-cmd-lang/src/example_support.rs index 5b9b0b3a07..42dcd447b7 100644 --- a/crates/nu-cmd-lang/src/example_support.rs +++ b/crates/nu-cmd-lang/src/example_support.rs @@ -306,10 +306,6 @@ impl<'a> std::fmt::Debug for DebuggableValue<'a> { Value::Custom { val, .. } => { write!(f, "CustomValue({:?})", val) } - Value::LazyRecord { val, .. } => { - let rec = val.collect().map_err(|_| std::fmt::Error)?; - write!(f, "LazyRecord({:?})", DebuggableValue(&rec)) - } } } } diff --git a/crates/nu-color-config/src/style_computer.rs b/crates/nu-color-config/src/style_computer.rs index 3d21e1583c..cd2454f011 100644 --- a/crates/nu-color-config/src/style_computer.rs +++ b/crates/nu-color-config/src/style_computer.rs @@ -106,10 +106,9 @@ impl<'a> StyleComputer<'a> { Value::Binary { .. } => TextStyle::with_style(Left, s), Value::CellPath { .. } => TextStyle::with_style(Left, s), Value::Record { .. } | Value::List { .. } => TextStyle::with_style(Left, s), - Value::Closure { .. } - | Value::Custom { .. } - | Value::Error { .. } - | Value::LazyRecord { .. } => TextStyle::basic_left(), + Value::Closure { .. } | Value::Custom { .. } | Value::Error { .. } => { + TextStyle::basic_left() + } } } diff --git a/crates/nu-command/src/debug/explain.rs b/crates/nu-command/src/debug/explain.rs index bdfb61bb48..0abd87b9a3 100644 --- a/crates/nu-command/src/debug/explain.rs +++ b/crates/nu-command/src/debug/explain.rs @@ -272,10 +272,6 @@ pub fn debug_string_without_formatting(value: &Value) -> String { .collect::>() .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. Value::Closure { val, .. } => format!("", val.block_id), Value::Nothing { .. } => String::new(), diff --git a/crates/nu-command/src/debug/info.rs b/crates/nu-command/src/debug/info.rs index 711fd58c16..76317ed866 100644 --- a/crates/nu-command/src/debug/info.rs +++ b/crates/nu-command/src/debug/info.rs @@ -1,5 +1,4 @@ use nu_engine::command_prelude::*; -use nu_protocol::LazyRecord; use sysinfo::{MemoryRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System}; const ENV_PATH_SEPARATOR_CHAR: char = { @@ -39,14 +38,10 @@ impl Command for DebugInfo { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - let span = Span::unknown(); - - let record = LazySystemInfoRecord { span }; - - Ok(Value::lazy_record(Box::new(record), span).into_pipeline_data()) + Ok(all_columns(call.head).into_pipeline_data()) } fn examples(&self) -> Vec { @@ -58,207 +53,119 @@ impl Command for DebugInfo { } } -#[derive(Debug, Clone)] -struct LazySystemInfoRecord { - span: Span, -} +fn all_columns(span: Span) -> Value { + let rk = RefreshKind::new() + .with_processes(ProcessRefreshKind::everything()) + .with_memory(MemoryRefreshKind::everything()); -impl LazySystemInfoRecord { - fn get_column_value_with_system( - &self, - column: &str, - system_option: Option<&System>, - ) -> Result { - let pid = Pid::from(std::process::id() as usize); - match column { - "thread_id" => Ok(Value::int(get_thread_id() as i64, self.span)), - "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()) - })); + // only get information requested + let sys = System::new_with_specifics(rk); - let system = system_opt.get_system(); - // get the process information for the nushell pid - let pinfo = system.process(pid); + let pid = Pid::from(std::process::id() as usize); + let ppid = { + sys.process(pid) + .and_then(|p| p.parent()) + .map(|p| Value::int(p.as_u32().into(), span)) + .unwrap_or(Value::nothing(span)) + }; - Ok(pinfo - .and_then(|p| p.parent()) - .map(|p| Value::int(p.as_u32() as i64, self.span)) - .unwrap_or(Value::nothing(self.span))) - } - "system" => { - // only get information requested - let system_opt = SystemOpt::from((system_option, || { - RefreshKind::new().with_memory(MemoryRefreshKind::everything()) - })); + let system = Value::record( + record! { + "total_memory" => Value::filesize(sys.total_memory() as i64, span), + "free_memory" => Value::filesize(sys.free_memory() as i64, span), + "used_memory" => Value::filesize(sys.used_memory() as i64, span), + "available_memory" => Value::filesize(sys.available_memory() as i64, span), + }, + span, + ); - let system = system_opt.get_system(); + let process = if let Some(p) = sys.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) + }; - Ok(Value::record( - record! { - "total_memory" => Value::filesize(system.total_memory() as i64, self.span), - "free_memory" => Value::filesize(system.free_memory() as i64, self.span), - "used_memory" => Value::filesize(system.used_memory() as i64, self.span), - "available_memory" => Value::filesize(system.available_memory() as i64, self.span), - }, - self.span, - )) - } - "process" => { - // only get information requested - let system_opt = SystemOpt::from((system_option, || { - RefreshKind::new().with_processes(ProcessRefreshKind::everything()) - })); + let cwd = if let Some(path) = p.cwd() { + Value::string(path.to_string_lossy().to_string(), span) + } else { + Value::nothing(span) + }; - let system = system_opt.get_system(); - let pinfo = system.process(pid); + let exe_path = if let Some(path) = p.exe() { + Value::string(path.to_string_lossy().to_string(), span) + } else { + Value::nothing(span) + }; - if let Some(p) = pinfo { - Ok(Value::record( - 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 { - Value::nothing(self.span) - } - }, - "cwd" => { - if let Some(path) = p.cwd() { - Value::string(path.to_string_lossy().to_string(), self.span) - }else{ - Value::nothing(self.span) - } - }, - "exe_path" => { - 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(); - for val in p.environ() { - if let Some((key, value)) = val.split_once('=') { - let is_env_var_a_list = { - { - #[cfg(target_family = "windows")] - { - key == "Path" || key == "PATHEXT" || key == "PSMODULEPATH" || key == "PSModulePath" - } - #[cfg(not(target_family = "windows"))] - { - key == "PATH" || key == "DYLD_FALLBACK_LIBRARY_PATH" - } - } - }; - if is_env_var_a_list { - let items = value.split(ENV_PATH_SEPARATOR_CHAR).map(|r| Value::string(r.to_string(), self.span)).collect::>(); - env_rec.push(key.to_string(), Value::list(items, self.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(), self.span)).collect::>(); - env_rec.push(key.to_string(), Value::list(items, self.span)); - } else { - env_rec.push(key.to_string(), Value::string(value.to_string(), self.span)); - } - } - } - Value::record(env_rec, self.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( - record! { - "total_memory" => Value::filesize(system.total_memory() as i64, self.span), - "free_memory" => Value::filesize(system.free_memory() as i64, self.span), - "used_memory" => Value::filesize(system.used_memory() as i64, self.span), - "available_memory" => Value::filesize(system.available_memory() as i64, self.span), - }, - self.span, - )) + let environment = { + let mut env_rec = Record::new(); + for val in p.environ() { + if let Some((key, value)) = val.split_once('=') { + let is_env_var_a_list = { + { + #[cfg(target_family = "windows")] + { + key == "Path" + || key == "PATHEXT" + || key == "PSMODULEPATH" + || key == "PSModulePath" + } + #[cfg(not(target_family = "windows"))] + { + key == "PATH" || key == "DYLD_FALLBACK_LIBRARY_PATH" + } + } + }; + if is_env_var_a_list { + let items = value + .split(ENV_PATH_SEPARATOR_CHAR) + .map(|r| Value::string(r.to_string(), span)) + .collect::>(); + 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::>(); + env_rec.push(key.to_string(), Value::list(items, span)); + } else { + env_rec.push(key.to_string(), Value::string(value.to_string(), span)); + } } } - _ => Err(ShellError::IncompatibleParametersSingle { - msg: format!("Unknown column: {}", column), - span: self.span, - }), - } - } -} + Value::record(env_rec, span) + }; -impl<'a> LazyRecord<'a> for LazySystemInfoRecord { - fn column_names(&'a self) -> Vec<&'a str> { - vec!["thread_id", "pid", "ppid", "process", "system"] - } + Value::record( + record! { + "memory" => Value::filesize(p.memory() as i64, span), + "virtual_memory" => Value::filesize(p.virtual_memory() as i64, span), + "status" => Value::string(p.status().to_string(), span), + "root" => root, + "cwd" => cwd, + "exe_path" => exe_path, + "command" => Value::string(p.cmd().join(" "), span), + "name" => Value::string(p.name(), span), + "environment" => environment, + }, + span, + ) + } else { + Value::nothing(span) + }; - fn get_column_value(&self, column: &str) -> Result { - self.get_column_value_with_system(column, None) - } - - 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 { - 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::>() - .map(|record| Value::record(record, self.span())) - } -} - -enum SystemOpt<'a> { - Ptr(&'a System), - Owned(Box), -} - -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()))), - } - } + Value::record( + record! { + "thread_id" => Value::int(get_thread_id() as i64, span), + "pid" => Value::int(pid.as_u32().into(), span), + "ppid" => ppid, + "system" => system, + "process" => process, + }, + span, + ) } fn get_thread_id() -> u64 { diff --git a/crates/nu-command/src/filters/columns.rs b/crates/nu-command/src/filters/columns.rs index a5b0f2b9ea..44b713e793 100644 --- a/crates/nu-command/src/filters/columns.rs +++ b/crates/nu-command/src/filters/columns.rs @@ -105,18 +105,6 @@ fn getcol( .into_pipeline_data(ctrlc) .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 .into_owned() .into_iter() diff --git a/crates/nu-command/src/filters/find.rs b/crates/nu-command/src/filters/find.rs index 9cc140ece1..6efda0d836 100644 --- a/crates/nu-command/src/filters/find.rs +++ b/crates/nu-command/src/filters/find.rs @@ -533,15 +533,6 @@ fn value_should_be_printed( Value::Record { val, .. } => { 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, }); if invert { diff --git a/crates/nu-command/src/filters/items.rs b/crates/nu-command/src/filters/items.rs index 8dca421200..5a97a5a3db 100644 --- a/crates/nu-command/src/filters/items.rs +++ b/crates/nu-command/src/filters/items.rs @@ -44,12 +44,6 @@ impl Command for Items { match input { PipelineData::Empty => Ok(PipelineData::Empty), PipelineData::Value(value, ..) => { - let value = if let Value::LazyRecord { val, .. } = value { - val.collect()? - } else { - value - }; - let span = value.span(); match value { Value::Record { val, .. } => { diff --git a/crates/nu-command/src/filters/values.rs b/crates/nu-command/src/filters/values.rs index 344ffc96c0..8b35352150 100644 --- a/crates/nu-command/src/filters/values.rs +++ b/crates/nu-command/src/filters/values.rs @@ -161,20 +161,6 @@ fn values( .cloned() .collect::>() .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 Value::Error { error, .. } => Err(*error), other => Err(ShellError::OnlySupportsThisInputType { diff --git a/crates/nu-command/src/formats/to/json.rs b/crates/nu-command/src/formats/to/json.rs index c48daad085..0796abc8dc 100644 --- a/crates/nu-command/src/formats/to/json.rs +++ b/crates/nu-command/src/formats/to/json.rs @@ -135,10 +135,6 @@ pub fn value_to_json_value(v: &Value) -> Result { } nu_json::Value::Object(m) } - Value::LazyRecord { val, .. } => { - let collected = val.collect()?; - value_to_json_value(&collected)? - } Value::Custom { val, .. } => { let collected = val.to_base_value(span)?; value_to_json_value(&collected)? diff --git a/crates/nu-command/src/formats/to/msgpack.rs b/crates/nu-command/src/formats/to/msgpack.rs index 9e484eb1bd..a4575f37e4 100644 --- a/crates/nu-command/src/formats/to/msgpack.rs +++ b/crates/nu-command/src/formats/to/msgpack.rs @@ -246,9 +246,6 @@ pub(crate) fn write_value( Value::Custom { val, .. } => { write_value(out, &val.to_base_value(span)?, depth)?; } - Value::LazyRecord { val, .. } => { - write_value(out, &val.collect()?, depth)?; - } } Ok(()) } diff --git a/crates/nu-command/src/formats/to/text.rs b/crates/nu-command/src/formats/to/text.rs index 362786f1c0..2515ca5f92 100644 --- a/crates/nu-command/src/formats/to/text.rs +++ b/crates/nu-command/src/formats/to/text.rs @@ -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))) .collect::>() .join(separator), - Value::LazyRecord { val, .. } => match val.collect() { - Ok(val) => local_into_string(val, separator, config), - Err(error) => format!("{error:?}"), - }, Value::Closure { val, .. } => format!("", val.block_id), Value::Nothing { .. } => String::new(), Value::Error { error, .. } => format!("{error:?}"), diff --git a/crates/nu-command/src/formats/to/toml.rs b/crates/nu-command/src/formats/to/toml.rs index adfdf7f39a..385e9576f3 100644 --- a/crates/nu-command/src/formats/to/toml.rs +++ b/crates/nu-command/src/formats/to/toml.rs @@ -62,10 +62,6 @@ fn helper(engine_state: &EngineState, v: &Value) -> Result { - let collected = val.collect()?; - helper(engine_state, &collected)? - } Value::List { vals, .. } => toml::Value::Array(toml_list(engine_state, vals)?), Value::Closure { .. } => { let code = engine_state.get_span_contents(span); diff --git a/crates/nu-command/src/formats/to/yaml.rs b/crates/nu-command/src/formats/to/yaml.rs index d8cdaac725..d03c886328 100644 --- a/crates/nu-command/src/formats/to/yaml.rs +++ b/crates/nu-command/src/formats/to/yaml.rs @@ -62,10 +62,6 @@ pub fn value_to_yaml_value(v: &Value) -> Result { } serde_yaml::Value::Mapping(m) } - Value::LazyRecord { val, .. } => { - let collected = val.collect()?; - value_to_yaml_value(&collected)? - } Value::List { vals, .. } => { let mut out = vec![]; diff --git a/crates/nu-command/src/system/sys.rs b/crates/nu-command/src/system/sys.rs index 1fe41ac7c2..0a836f894a 100644 --- a/crates/nu-command/src/system/sys.rs +++ b/crates/nu-command/src/system/sys.rs @@ -1,6 +1,5 @@ use chrono::{DateTime, Local}; use nu_engine::command_prelude::*; -use nu_protocol::LazyRecord; use std::time::{Duration, UNIX_EPOCH}; use sysinfo::{ Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL, @@ -32,10 +31,7 @@ impl Command for Sys { call: &Call, _input: PipelineData, ) -> Result { - let span = call.span(); - let ret = Value::lazy_record(Box::new(SysResult { span }), span); - - Ok(ret.into_pipeline_data()) + Ok(all_columns(call.head).into_pipeline_data()) } fn examples(&self) -> Vec { @@ -64,36 +60,18 @@ pub struct SysResult { pub span: Span, } -impl LazyRecord<'_> for SysResult { - fn column_names(&self) -> Vec<&'static str> { - vec!["host", "cpu", "disks", "mem", "temp", "net"] - } - - fn get_column_value(&self, column: &str) -> Result { - let span = self.span; - - match column { - "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, - }), - } - } - - fn span(&self) -> Span { - self.span - } - - fn clone_value(&self, span: Span) -> Value { - Value::lazy_record(Box::new((*self).clone()), span) - } +fn all_columns(span: Span) -> Value { + Value::record( + record! { + "host" => host(span), + "cpu" => cpu(span), + "disks" => disks(span), + "mem" => mem(span), + "temp" => temp(span), + "net" => net(span), + }, + span, + ) } pub fn trim_cstyle_null(s: String) -> String { diff --git a/crates/nu-command/src/viewers/table.rs b/crates/nu-command/src/viewers/table.rs index 11731e61b9..e7d2774a5e 100644 --- a/crates/nu-command/src/viewers/table.rs +++ b/crates/nu-command/src/viewers/table.rs @@ -394,10 +394,6 @@ fn handle_table_command( input.data = PipelineData::Empty; 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, .. }, ..) => { // Propagate this error outward, so that it goes to stderr // instead of stdout. diff --git a/crates/nu-command/tests/commands/insert.rs b/crates/nu-command/tests/commands/insert.rs index 400319c4f0..c77fb6c867 100644 --- a/crates/nu-command/tests/commands/insert.rs +++ b/crates/nu-command/tests/commands/insert.rs @@ -98,21 +98,6 @@ fn insert_uses_enumerate_index() { 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] fn deep_cell_path_creates_all_nested_records() { let actual = nu!("{a: {}} | insert a.b.c 0 | get a.b.c"); diff --git a/crates/nu-command/tests/commands/update.rs b/crates/nu-command/tests/commands/update.rs index 2e74657f7c..876ed471e5 100644 --- a/crates/nu-command/tests/commands/update.rs +++ b/crates/nu-command/tests/commands/update.rs @@ -103,13 +103,6 @@ fn update_uses_enumerate_index() { 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] fn list_replacement_closure() { let actual = nu!("[1, 2] | update 1 {|i| $i + 1 } | to nuon"); diff --git a/crates/nu-command/tests/commands/upsert.rs b/crates/nu-command/tests/commands/upsert.rs index 1bb823e88c..0ce8307e70 100644 --- a/crates/nu-command/tests/commands/upsert.rs +++ b/crates/nu-command/tests/commands/upsert.rs @@ -112,17 +112,6 @@ fn upsert_past_end_of_list_stream() { .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] fn deep_cell_path_creates_all_nested_records() { let actual = nu!("{a: {}} | upsert a.b.c 0 | get a.b.c"); diff --git a/crates/nu-explore/src/nu_common/value.rs b/crates/nu-explore/src/nu_common/value.rs index 2c2c858db0..c61533770b 100644 --- a/crates/nu-explore/src/nu_common/value.rs +++ b/crates/nu-explore/src/nu_common/value.rs @@ -112,10 +112,6 @@ pub fn collect_input(value: Value) -> Result<(Vec, Vec>)> { Ok((vec![String::from("")], lines)) } - Value::LazyRecord { val, .. } => { - let materialized = val.collect()?; - collect_input(materialized) - } Value::Nothing { .. } => Ok((vec![], vec![])), Value::Custom { val, .. } => { let materialized = val.to_base_value(span)?; diff --git a/crates/nu-plugin-core/src/util/with_custom_values_in.rs b/crates/nu-plugin-core/src/util/with_custom_values_in.rs index f9b12223ab..8fcd843ac4 100644 --- a/crates/nu-plugin-core/src/util/with_custom_values_in.rs +++ b/crates/nu-plugin-core/src/util/with_custom_values_in.rs @@ -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 /// plugin custom values. -/// -/// `LazyRecord`s will be collected to plain values for completeness. pub fn with_custom_values_in( value: &mut Value, mut f: impl FnMut(Spanned<&mut Box>) -> Result<(), E>, @@ -18,13 +16,6 @@ where // Operate on a CustomValue. 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(()), } }) @@ -33,31 +24,7 @@ where #[test] fn find_custom_values() { use nu_plugin_protocol::test_util::test_plugin_custom_value; - use nu_protocol::{engine::Closure, record, LazyRecord, Span}; - - #[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 { - 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) - } - } + use nu_protocol::{engine::Closure, record}; 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"))] } ), - "lazy" => Value::test_lazy_record(Box::new(Lazy)), }); // Do with_custom_values_in, and count the number of custom values found @@ -83,7 +49,7 @@ fn find_custom_values() { Ok(()) }) .expect("error"); - assert_eq!(4, found, "found in value"); + assert_eq!(3, found, "found in value"); // Try it on bare custom value too found = 0; diff --git a/crates/nu-plugin-protocol/src/plugin_custom_value/mod.rs b/crates/nu-plugin-protocol/src/plugin_custom_value/mod.rs index e8e83d76d2..ea2b1551c9 100644 --- a/crates/nu-plugin-protocol/src/plugin_custom_value/mod.rs +++ b/crates/nu-plugin-protocol/src/plugin_custom_value/mod.rs @@ -179,11 +179,6 @@ impl PluginCustomValue { Ok(()) } } - // Collect LazyRecord before proceeding - Value::LazyRecord { ref val, .. } => { - *value = val.collect()?; - Ok(()) - } _ => Ok(()), } }) @@ -205,11 +200,6 @@ impl PluginCustomValue { Ok(()) } } - // Collect LazyRecord before proceeding - Value::LazyRecord { ref val, .. } => { - *value = val.collect()?; - Ok(()) - } _ => Ok(()), } }) @@ -224,11 +214,6 @@ impl PluginCustomValue { *value = val.to_base_value(span)?; Ok(()) } - // Collect LazyRecord before proceeding - Value::LazyRecord { ref val, .. } => { - *value = val.collect()?; - Ok(()) - } _ => Ok(()), } }) diff --git a/crates/nu-plugin-test-support/src/plugin_test.rs b/crates/nu-plugin-test-support/src/plugin_test.rs index f4fc85e440..16eb62cf2e 100644 --- a/crates/nu-plugin-test-support/src/plugin_test.rs +++ b/crates/nu-plugin-test-support/src/plugin_test.rs @@ -344,9 +344,6 @@ impl PluginTest { // All equal, and same length 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. _ => Ok(a == b), } diff --git a/crates/nu-plugin/src/plugin/command.rs b/crates/nu-plugin/src/plugin/command.rs index 8678743524..ad8ecd7d9c 100644 --- a/crates/nu-plugin/src/plugin/command.rs +++ b/crates/nu-plugin/src/plugin/command.rs @@ -381,11 +381,6 @@ pub(crate) fn render_examples( plugin.custom_value_to_base_value(engine, val.into_spanned(span))?; Ok::<_, ShellError>(()) } - // Collect LazyRecord before proceeding - Value::LazyRecord { ref val, .. } => { - *value = val.collect()?; - Ok(()) - } _ => Ok(()), } })?; diff --git a/crates/nu-protocol/src/errors/shell_error.rs b/crates/nu-protocol/src/errors/shell_error.rs index 48d2ec88e8..e1d7ade338 100644 --- a/crates/nu-protocol/src/errors/shell_error.rs +++ b/crates/nu-protocol/src/errors/shell_error.rs @@ -1178,16 +1178,6 @@ pub enum ShellError { span: Option, }, - /// 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 #[error("Operation interrupted by user")] InterruptedByUser { diff --git a/crates/nu-protocol/src/value/lazy_record.rs b/crates/nu-protocol/src/value/lazy_record.rs deleted file mode 100644 index f4f0f93b0a..0000000000 --- a/crates/nu-protocol/src/value/lazy_record.rs +++ /dev/null @@ -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; - - fn span(&self) -> Span; - - // Convert the lazy record into a regular Value::Record by collecting all its columns - fn collect(&'a self) -> Result { - self.column_names() - .into_iter() - .map(|col| { - let val = self.get_column_value(col)?; - Ok((col.to_owned(), val)) - }) - .collect::>() - .map(|record| Value::record(record, self.span())) - } - - fn clone_value(&self, span: Span) -> Value; -} diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 64b5abf64d..dbfa93b793 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -4,7 +4,6 @@ mod filesize; mod from; mod from_value; mod glob; -mod lazy_record; mod range; pub mod record; @@ -13,7 +12,6 @@ pub use duration::*; pub use filesize::*; pub use from_value::FromValue; pub use glob::*; -pub use lazy_record::LazyRecord; pub use range::{FloatRange, IntRange, Range}; pub use record::Record; @@ -164,13 +162,6 @@ pub enum Value { #[serde(rename = "span")] internal_span: Span, }, - #[serde(skip)] - LazyRecord { - val: Box 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 { @@ -212,7 +203,6 @@ impl Clone for Value { val: val.clone(), internal_span: *internal_span, }, - Value::LazyRecord { val, internal_span } => val.clone_value(*internal_span), Value::List { vals, 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 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 pub fn span(&self) -> Span { match self { @@ -709,7 +681,6 @@ impl Value { | Value::Binary { internal_span, .. } | Value::CellPath { internal_span, .. } | Value::Custom { internal_span, .. } - | Value::LazyRecord { internal_span, .. } | Value::Error { internal_span, .. } => *internal_span, } } @@ -727,7 +698,6 @@ impl Value { | Value::String { internal_span, .. } | Value::Glob { internal_span, .. } | Value::Record { internal_span, .. } - | Value::LazyRecord { internal_span, .. } | Value::List { internal_span, .. } | Value::Closure { internal_span, .. } | Value::Nothing { internal_span, .. } @@ -784,10 +754,6 @@ impl Value { 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::Closure { .. } => Type::Closure, Value::Error { .. } => Type::Error, @@ -893,10 +859,6 @@ impl Value { .collect::>() .join(separator) ), - Value::LazyRecord { val, .. } => val - .collect() - .unwrap_or_else(|err| Value::error(err, span)) - .to_expanded_string(separator, config), Value::Closure { val, .. } => format!("", val.block_id), Value::Nothing { .. } => String::new(), Value::Error { error, .. } => format!("{error:?}"), @@ -919,7 +881,6 @@ impl Value { /// - "[list {n} items]" /// - "[record {n} fields]" pub fn to_abbreviated_string(&self, config: &Config) -> String { - let span = self.span(); match self { Value::Date { val, .. } => match &config.datetime_table_format { Some(format) => self.format_datetime(val, format), @@ -945,10 +906,6 @@ impl Value { val.len(), 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), } } @@ -1087,7 +1044,7 @@ impl Value { } // Records (and tables) are the only built-in which support column names, // so only use this message for them. - Value::Record { .. } | Value::LazyRecord { .. } => { + Value::Record { .. } => { return Err(ShellError::TypeMismatch { err_message:"Can't access record values with a row index. Try specifying a column name instead".into(), 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. // Create a List which contains each matching value for contained // records in the source list. @@ -1327,11 +1258,6 @@ impl Value { 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()), v => { 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()), v => { return Err(ShellError::CantFindColumn { @@ -1532,11 +1453,6 @@ impl Value { } Ok(()) } - Value::LazyRecord { val, .. } => { - // convert to Record first. - *self = val.collect()?; - self.remove_data_at_cell_path(cell_path) - } v => Err(ShellError::CantFindColumn { col_name: col_name.clone(), span: *span, @@ -1616,11 +1532,6 @@ impl Value { } Ok(()) } - Value::LazyRecord { val, .. } => { - // convert to Record first. - *self = val.collect()?; - self.remove_data_at_cell_path(cell_path) - } v => Err(ShellError::CantFindColumn { col_name: col_name.clone(), span: *span, @@ -1739,11 +1650,6 @@ impl Value { 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 => { return Err(ShellError::UnsupportedInput { msg: "table or record".into(), @@ -1797,8 +1703,6 @@ impl Value { /// /// 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. pub fn recurse_mut( &mut self, @@ -1837,7 +1741,7 @@ impl Value { | Value::Binary { .. } | Value::CellPath { .. } => Ok(()), // 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 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 /// when used in errors. pub fn test_bool(val: bool) -> Value { @@ -2101,17 +1998,11 @@ impl Value { 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 LazyRecord<'a>>) -> Value { - Value::lazy_record(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. /// /// 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 { vec![ Value::test_bool(false), @@ -2127,7 +2018,6 @@ impl Value { Value::test_float(0.0), Value::test_string(String::new()), Value::test_record(Record::new()), - // Value::test_lazy_record(Box::new(todo!())), Value::test_list(Vec::new()), Value::test_closure(Closure { block_id: 0, @@ -2181,7 +2071,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Less), Value::Glob { .. } => Some(Ordering::Less), Value::Record { .. } => Some(Ordering::Less), - Value::LazyRecord { .. } => Some(Ordering::Less), Value::List { .. } => Some(Ordering::Less), Value::Closure { .. } => Some(Ordering::Less), Value::Nothing { .. } => Some(Ordering::Less), @@ -2201,7 +2090,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Less), Value::Glob { .. } => Some(Ordering::Less), Value::Record { .. } => Some(Ordering::Less), - Value::LazyRecord { .. } => Some(Ordering::Less), Value::List { .. } => Some(Ordering::Less), Value::Closure { .. } => Some(Ordering::Less), Value::Nothing { .. } => Some(Ordering::Less), @@ -2221,7 +2109,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Less), Value::Glob { .. } => Some(Ordering::Less), Value::Record { .. } => Some(Ordering::Less), - Value::LazyRecord { .. } => Some(Ordering::Less), Value::List { .. } => Some(Ordering::Less), Value::Closure { .. } => Some(Ordering::Less), Value::Nothing { .. } => Some(Ordering::Less), @@ -2241,7 +2128,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Less), Value::Glob { .. } => Some(Ordering::Less), Value::Record { .. } => Some(Ordering::Less), - Value::LazyRecord { .. } => Some(Ordering::Less), Value::List { .. } => Some(Ordering::Less), Value::Closure { .. } => Some(Ordering::Less), Value::Nothing { .. } => Some(Ordering::Less), @@ -2261,7 +2147,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Less), Value::Glob { .. } => Some(Ordering::Less), Value::Record { .. } => Some(Ordering::Less), - Value::LazyRecord { .. } => Some(Ordering::Less), Value::List { .. } => Some(Ordering::Less), Value::Closure { .. } => Some(Ordering::Less), Value::Nothing { .. } => Some(Ordering::Less), @@ -2281,7 +2166,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Less), Value::Glob { .. } => Some(Ordering::Less), Value::Record { .. } => Some(Ordering::Less), - Value::LazyRecord { .. } => Some(Ordering::Less), Value::List { .. } => Some(Ordering::Less), Value::Closure { .. } => Some(Ordering::Less), Value::Nothing { .. } => Some(Ordering::Less), @@ -2301,7 +2185,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Less), Value::Glob { .. } => Some(Ordering::Less), Value::Record { .. } => Some(Ordering::Less), - Value::LazyRecord { .. } => Some(Ordering::Less), Value::List { .. } => Some(Ordering::Less), Value::Closure { .. } => 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::Glob { val: rhs, .. } => lhs.partial_cmp(rhs), Value::Record { .. } => Some(Ordering::Less), - Value::LazyRecord { .. } => Some(Ordering::Less), Value::List { .. } => Some(Ordering::Less), Value::Closure { .. } => 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::Glob { val: rhs, .. } => lhs.partial_cmp(rhs), Value::Record { .. } => Some(Ordering::Less), - Value::LazyRecord { .. } => Some(Ordering::Less), Value::List { .. } => Some(Ordering::Less), Value::Closure { .. } => 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 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::Closure { .. } => Some(Ordering::Less), Value::Nothing { .. } => Some(Ordering::Less), @@ -2413,7 +2287,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Greater), Value::Glob { .. } => Some(Ordering::Greater), Value::Record { .. } => Some(Ordering::Greater), - Value::LazyRecord { .. } => Some(Ordering::Greater), Value::List { vals: rhs, .. } => lhs.partial_cmp(rhs), Value::Closure { .. } => Some(Ordering::Less), Value::Nothing { .. } => Some(Ordering::Less), @@ -2433,7 +2306,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Greater), Value::Glob { .. } => Some(Ordering::Greater), Value::Record { .. } => Some(Ordering::Greater), - Value::LazyRecord { .. } => Some(Ordering::Greater), Value::List { .. } => Some(Ordering::Greater), Value::Closure { val: rhs, .. } => lhs.block_id.partial_cmp(&rhs.block_id), Value::Nothing { .. } => Some(Ordering::Less), @@ -2453,7 +2325,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Greater), Value::Glob { .. } => Some(Ordering::Greater), Value::Record { .. } => Some(Ordering::Greater), - Value::LazyRecord { .. } => Some(Ordering::Greater), Value::List { .. } => Some(Ordering::Greater), Value::Closure { .. } => Some(Ordering::Greater), Value::Nothing { .. } => Some(Ordering::Equal), @@ -2473,7 +2344,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Greater), Value::Glob { .. } => Some(Ordering::Greater), Value::Record { .. } => Some(Ordering::Greater), - Value::LazyRecord { .. } => Some(Ordering::Greater), Value::List { .. } => Some(Ordering::Greater), Value::Closure { .. } => Some(Ordering::Greater), Value::Nothing { .. } => Some(Ordering::Greater), @@ -2493,7 +2363,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Greater), Value::Glob { .. } => Some(Ordering::Greater), Value::Record { .. } => Some(Ordering::Greater), - Value::LazyRecord { .. } => Some(Ordering::Greater), Value::List { .. } => Some(Ordering::Greater), Value::Closure { .. } => Some(Ordering::Greater), Value::Nothing { .. } => Some(Ordering::Greater), @@ -2513,7 +2382,6 @@ impl PartialOrd for Value { Value::String { .. } => Some(Ordering::Greater), Value::Glob { .. } => Some(Ordering::Greater), Value::Record { .. } => Some(Ordering::Greater), - Value::LazyRecord { .. } => Some(Ordering::Greater), Value::List { .. } => Some(Ordering::Greater), Value::Closure { .. } => Some(Ordering::Greater), Value::Nothing { .. } => Some(Ordering::Greater), @@ -2523,13 +2391,6 @@ impl PartialOrd for Value { Value::Custom { .. } => Some(Ordering::Less), }, (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 - } - } } } } diff --git a/crates/nuon/src/to.rs b/crates/nuon/src/to.rs index 8e9ce71f58..8b69f17a87 100644 --- a/crates/nuon/src/to.rs +++ b/crates/nuon/src/to.rs @@ -221,10 +221,6 @@ fn value_to_string( 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' // (could be mistaken for commands by the Nu parser) Value::String { val, .. } => Ok(escape_quote_string(val)),