From 1c49ca503a4bf36586cc750e1e931cf140177f2f Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Sat, 17 Feb 2024 18:14:16 +0000 Subject: [PATCH] Name the `Value` conversion functions more clearly (#11851) # Description This PR renames the conversion functions on `Value` to be more consistent. It follows the Rust [API guidelines](https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv) for ad-hoc conversions. The conversion functions on `Value` now come in a few forms: - `coerce_{type}` takes a `&Value` and attempts to convert the value to `type` (e.g., `i64` are converted to `f64`). This is the old behavior of some of the `as_{type}` functions -- these functions have simply been renamed to better reflect what they do. - The new `as_{type}` functions take a `&Value` and returns an `Ok` result only if the value is of `type` (no conversion is attempted). The returned value will be borrowed if `type` is non-`Copy`, otherwise an owned value is returned. - `into_{type}` exists for non-`Copy` types, but otherwise does not attempt conversion just like `as_type`. It takes an owned `Value` and always returns an owned result. - `coerce_into_{type}` has the same relationship with `coerce_{type}` as `into_{type}` does with `as_{type}`. - `to_{kind}_string`: conversion to different string formats (debug, abbreviated, etc.). Only two of the old string conversion functions were removed, the rest have been renamed only. - `to_{type}`: other conversion functions. Currently, only `to_path` exists. (And `to_string` through `Display`.) This table summaries the above: | Form | Cost | Input Ownership | Output Ownership | Converts `Value` case/`type` | | ---------------------------- | ----- | --------------- | ---------------- | -------- | | `as_{type}` | Cheap | Borrowed | Borrowed/Owned | No | | `into_{type}` | Cheap | Owned | Owned | No | | `coerce_{type}` | Cheap | Borrowed | Borrowed/Owned | Yes | | `coerce_into_{type}` | Cheap | Owned | Owned | Yes | | `to_{kind}_string` | Expensive | Borrowed | Owned | Yes | | `to_{type}` | Expensive | Borrowed | Owned | Yes | # User-Facing Changes Breaking API change for `Value` in `nu-protocol` which is exposed as part of the plugin API. --- crates/nu-cli/src/commands/commandline.rs | 20 +- .../nu-cli/src/commands/keybindings_listen.rs | 2 +- .../src/completions/command_completions.rs | 2 +- crates/nu-cli/src/completions/completer.rs | 6 +- .../src/completions/custom_completions.rs | 2 +- .../src/completions/dotnu_completions.rs | 2 +- crates/nu-cli/src/eval_cmds.rs | 4 +- crates/nu-cli/src/eval_file.rs | 2 +- crates/nu-cli/src/menus/help_completions.rs | 4 +- crates/nu-cli/src/menus/menu_completions.rs | 6 +- crates/nu-cli/src/nu_highlight.rs | 3 +- crates/nu-cli/src/reedline_config.rs | 70 +- crates/nu-cli/src/repl.rs | 8 +- crates/nu-cmd-base/src/hook.rs | 2 +- crates/nu-cmd-base/src/util.rs | 2 +- .../values/nu_dataframe/conversion.rs | 4 +- .../src/dataframe/values/nu_schema.rs | 2 +- .../src/extra/filters/update_cells.rs | 15 +- .../nu-cmd-extra/src/extra/formats/to/html.rs | 2 +- .../src/extra/platform/ansi/gradient.rs | 2 +- .../src/extra/strings/format/command.rs | 6 +- .../src/matching_brackets_style.rs | 2 +- crates/nu-color-config/src/nu_style.rs | 2 +- crates/nu-command/src/charting/histogram.rs | 5 +- .../src/conversions/into/datetime.rs | 19 +- .../nu-command/src/conversions/into/string.rs | 6 +- .../nu-command/src/conversions/into/value.rs | 18 +- crates/nu-command/src/date/humanize.rs | 2 +- crates/nu-command/src/date/to_record.rs | 2 +- crates/nu-command/src/date/to_table.rs | 2 +- crates/nu-command/src/date/to_timezone.rs | 2 +- crates/nu-command/src/debug/debug_.rs | 4 +- crates/nu-command/src/debug/view_source.rs | 2 +- crates/nu-command/src/env/load_env.rs | 2 +- crates/nu-command/src/env/with_env.rs | 2 +- crates/nu-command/src/filesystem/cd.rs | 2 +- crates/nu-command/src/filesystem/open.rs | 11 +- crates/nu-command/src/filesystem/save.rs | 4 +- crates/nu-command/src/filters/find.rs | 32 +- crates/nu-command/src/filters/flatten.rs | 8 +- crates/nu-command/src/filters/group_by.rs | 6 +- crates/nu-command/src/filters/headers.rs | 2 +- crates/nu-command/src/filters/insert.rs | 8 +- crates/nu-command/src/filters/join.rs | 4 +- crates/nu-command/src/filters/move_.rs | 6 +- crates/nu-command/src/filters/sort.rs | 16 +- crates/nu-command/src/filters/split_by.rs | 8 +- crates/nu-command/src/filters/transpose.rs | 2 +- crates/nu-command/src/filters/update.rs | 6 +- crates/nu-command/src/filters/upsert.rs | 8 +- crates/nu-command/src/formats/from/yaml.rs | 4 +- crates/nu-command/src/formats/to/delimited.rs | 2 +- crates/nu-command/src/formats/to/md.rs | 10 +- crates/nu-command/src/generators/seq_date.rs | 4 +- crates/nu-command/src/misc/tutor.rs | 2 +- crates/nu-command/src/network/http/client.rs | 27 +- .../nu-command/src/network/url/build_query.rs | 2 +- crates/nu-command/src/network/url/join.rs | 14 +- crates/nu-command/src/network/url/parse.rs | 2 +- crates/nu-command/src/path/join.rs | 10 +- crates/nu-command/src/platform/ansi/ansi_.rs | 13 +- crates/nu-command/src/platform/ansi/strip.rs | 2 +- crates/nu-command/src/platform/input/list.rs | 4 +- crates/nu-command/src/random/float.rs | 6 +- crates/nu-command/src/sort_utils.rs | 17 +- crates/nu-command/src/stor/create.rs | 2 +- .../nu-command/src/strings/detect_columns.rs | 2 +- .../src/strings/encode_decode/encoding.rs | 6 +- crates/nu-command/src/strings/format/date.rs | 4 +- .../nu-command/src/strings/format/duration.rs | 2 +- .../nu-command/src/strings/format/filesize.rs | 2 +- crates/nu-command/src/strings/parse.rs | 15 +- crates/nu-command/src/strings/split/chars.rs | 2 +- crates/nu-command/src/strings/split/column.rs | 2 +- crates/nu-command/src/strings/split/list.rs | 8 +- crates/nu-command/src/strings/split/row.rs | 2 +- crates/nu-command/src/strings/split/words.rs | 2 +- crates/nu-command/src/strings/str_/expand.rs | 4 +- crates/nu-command/src/strings/str_/join.rs | 14 +- crates/nu-command/src/strings/str_/stats.rs | 2 +- .../nu-command/src/system/registry_query.rs | 8 +- crates/nu-command/src/system/run_external.rs | 2 +- crates/nu-command/src/viewers/griddle.rs | 15 +- .../tests/commands/database/into_sqlite.rs | 4 +- crates/nu-engine/src/documentation.rs | 12 +- crates/nu-engine/src/env.rs | 8 +- crates/nu-explore/src/commands/expand.rs | 2 +- crates/nu-explore/src/commands/nu.rs | 2 +- crates/nu-explore/src/lib.rs | 2 +- crates/nu-explore/src/pager/mod.rs | 2 +- crates/nu-explore/src/views/record/mod.rs | 6 +- crates/nu-parser/src/parse_keywords.rs | 16 +- crates/nu-parser/src/parser.rs | 2 +- crates/nu-protocol/src/config/helper.rs | 2 +- crates/nu-protocol/src/config/mod.rs | 8 +- crates/nu-protocol/src/config/table.rs | 4 +- crates/nu-protocol/src/engine/engine_state.rs | 4 +- .../src/engine/state_working_set.rs | 3 +- crates/nu-protocol/src/eval_base.rs | 4 +- crates/nu-protocol/src/pipeline_data.rs | 18 +- crates/nu-protocol/src/value/mod.rs | 939 ++++++++++-------- crates/nu-protocol/src/value/stream.rs | 4 +- crates/nu-protocol/tests/test_value.rs | 2 +- crates/nu-table/src/common.rs | 4 +- crates/nu-table/src/types/expanded.rs | 2 +- crates/nu-table/src/types/general.rs | 2 +- crates/nu-table/src/unstructured_table.rs | 2 +- crates/nu_plugin_formats/src/from/eml.rs | 2 +- crates/nu_plugin_formats/src/from/ics.rs | 2 +- crates/nu_plugin_formats/src/from/ini.rs | 2 +- crates/nu_plugin_formats/src/from/vcf.rs | 2 +- crates/nu_plugin_gstat/src/gstat.rs | 2 +- crates/nu_plugin_inc/src/inc.rs | 2 +- crates/nu_plugin_query/src/query_json.rs | 2 +- crates/nu_plugin_query/src/query_web.rs | 4 +- crates/nu_plugin_query/src/query_xml.rs | 2 +- src/test_bins.rs | 2 +- 117 files changed, 903 insertions(+), 745 deletions(-) diff --git a/crates/nu-cli/src/commands/commandline.rs b/crates/nu-cli/src/commands/commandline.rs index e160b68dce..973fe72315 100644 --- a/crates/nu-cli/src/commands/commandline.rs +++ b/crates/nu-cli/src/commands/commandline.rs @@ -70,11 +70,12 @@ impl Command for Commandline { _input: PipelineData, ) -> Result { if let Some(cmd) = call.opt::(engine_state, stack, 0)? { + let span = cmd.span(); + let cmd = cmd.coerce_into_string()?; let mut repl = engine_state.repl_state.lock().expect("repl state mutex"); if call.has_flag(engine_state, stack, "cursor")? { - let cmd_str = cmd.as_string()?; - match cmd_str.parse::() { + match cmd.parse::() { Ok(n) => { repl.cursor_pos = if n <= 0 { 0usize @@ -90,22 +91,19 @@ impl Command for Commandline { return Err(ShellError::CantConvert { to_type: "int".to_string(), from_type: "string".to_string(), - span: cmd.span(), - help: Some(format!( - r#"string "{cmd_str}" does not represent a valid int"# - )), + span, + help: Some(format!(r#"string "{cmd}" does not represent a valid int"#)), }) } } } else if call.has_flag(engine_state, stack, "append")? { - repl.buffer.push_str(&cmd.as_string()?); + repl.buffer.push_str(&cmd); } else if call.has_flag(engine_state, stack, "insert")? { - let cmd_str = cmd.as_string()?; let cursor_pos = repl.cursor_pos; - repl.buffer.insert_str(cursor_pos, &cmd_str); - repl.cursor_pos += cmd_str.len(); + repl.buffer.insert_str(cursor_pos, &cmd); + repl.cursor_pos += cmd.len(); } else { - repl.buffer = cmd.as_string()?; + repl.buffer = cmd; repl.cursor_pos = repl.buffer.len(); } Ok(Value::nothing(call.head).into_pipeline_data()) diff --git a/crates/nu-cli/src/commands/keybindings_listen.rs b/crates/nu-cli/src/commands/keybindings_listen.rs index aa69adcbb9..9049fc4d03 100644 --- a/crates/nu-cli/src/commands/keybindings_listen.rs +++ b/crates/nu-cli/src/commands/keybindings_listen.rs @@ -112,7 +112,7 @@ pub fn print_events(engine_state: &EngineState) -> Result { let o = match v { Value::Record { val, .. } => val .iter() - .map(|(x, y)| format!("{}: {}", x, y.into_string("", config))) + .map(|(x, y)| format!("{}: {}", x, y.to_expanded_string("", config))) .collect::>() .join(", "), diff --git a/crates/nu-cli/src/completions/command_completions.rs b/crates/nu-cli/src/completions/command_completions.rs index c7cc2c345e..131765e4bc 100644 --- a/crates/nu-cli/src/completions/command_completions.rs +++ b/crates/nu-cli/src/completions/command_completions.rs @@ -43,7 +43,7 @@ impl CommandCompletion { if let Some(paths) = paths { if let Ok(paths) = paths.as_list() { for path in paths { - let path = path.as_string().unwrap_or_default(); + let path = path.coerce_string().unwrap_or_default(); if let Ok(mut contents) = std::fs::read_dir(path) { while let Some(Ok(item)) = contents.next() { diff --git a/crates/nu-cli/src/completions/completer.rs b/crates/nu-cli/src/completions/completer.rs index 2459fca804..4c18e6701a 100644 --- a/crates/nu-cli/src/completions/completer.rs +++ b/crates/nu-cli/src/completions/completer.rs @@ -474,7 +474,7 @@ pub fn map_value_completions<'a>( ) -> Vec { list.filter_map(move |x| { // Match for string values - if let Ok(s) = x.as_string() { + if let Ok(s) = x.coerce_string() { return Some(Suggestion { value: s, description: None, @@ -507,7 +507,7 @@ pub fn map_value_completions<'a>( // Match `value` column if it.0 == "value" { // Convert the value to string - if let Ok(val_str) = it.1.as_string() { + if let Ok(val_str) = it.1.coerce_string() { // Update the suggestion value suggestion.value = val_str; } @@ -516,7 +516,7 @@ pub fn map_value_completions<'a>( // Match `description` column if it.0 == "description" { // Convert the value to string - if let Ok(desc_str) = it.1.as_string() { + if let Ok(desc_str) = it.1.coerce_string() { // Update the suggestion value suggestion.description = Some(desc_str); } diff --git a/crates/nu-cli/src/completions/custom_completions.rs b/crates/nu-cli/src/completions/custom_completions.rs index f8555c9d43..a9c680075c 100644 --- a/crates/nu-cli/src/completions/custom_completions.rs +++ b/crates/nu-cli/src/completions/custom_completions.rs @@ -117,7 +117,7 @@ impl Completer for CustomCompletion { }, match_algorithm: match options.get("completion_algorithm") { Some(option) => option - .as_string() + .coerce_string() .ok() .and_then(|option| option.try_into().ok()) .unwrap_or(MatchAlgorithm::Prefix), diff --git a/crates/nu-cli/src/completions/dotnu_completions.rs b/crates/nu-cli/src/completions/dotnu_completions.rs index a9bbf65ec0..fea082aabd 100644 --- a/crates/nu-cli/src/completions/dotnu_completions.rs +++ b/crates/nu-cli/src/completions/dotnu_completions.rs @@ -54,7 +54,7 @@ impl Completer for DotNuCompletion { .into_iter() .flat_map(|it| { it.iter().map(|x| { - x.as_path() + x.to_path() .expect("internal error: failed to convert lib path") }) }) diff --git a/crates/nu-cli/src/eval_cmds.rs b/crates/nu-cli/src/eval_cmds.rs index 83e546fd5b..887b3f76d4 100644 --- a/crates/nu-cli/src/eval_cmds.rs +++ b/crates/nu-cli/src/eval_cmds.rs @@ -28,7 +28,7 @@ pub fn evaluate_commands( let (block, delta) = { if let Some(ref t_mode) = table_mode { let mut config = engine_state.get_config().clone(); - config.table_mode = t_mode.as_string()?.parse().unwrap_or_default(); + config.table_mode = t_mode.coerce_string()?.parse().unwrap_or_default(); engine_state.set_config(config); } @@ -59,7 +59,7 @@ pub fn evaluate_commands( Ok(pipeline_data) => { let mut config = engine_state.get_config().clone(); if let Some(t_mode) = table_mode { - config.table_mode = t_mode.as_string()?.parse().unwrap_or_default(); + config.table_mode = t_mode.coerce_string()?.parse().unwrap_or_default(); } crate::eval_file::print_table_or_error(engine_state, stack, pipeline_data, &mut config) } diff --git a/crates/nu-cli/src/eval_file.rs b/crates/nu-cli/src/eval_file.rs index 6166920dd5..e94fc9859b 100644 --- a/crates/nu-cli/src/eval_file.rs +++ b/crates/nu-cli/src/eval_file.rs @@ -256,7 +256,7 @@ fn print_or_exit(pipeline_data: PipelineData, engine_state: &mut EngineState, co std::process::exit(1); } - let out = item.into_string("\n", config) + "\n"; + let out = item.to_expanded_string("\n", config) + "\n"; let _ = stdout_write_all_and_flush(out).map_err(|err| eprintln!("{err}")); } } diff --git a/crates/nu-cli/src/menus/help_completions.rs b/crates/nu-cli/src/menus/help_completions.rs index bcb07d6db0..90270415f6 100644 --- a/crates/nu-cli/src/menus/help_completions.rs +++ b/crates/nu-cli/src/menus/help_completions.rs @@ -57,7 +57,7 @@ impl NuHelpCompleter { if !sig.named.is_empty() { long_desc.push_str(&get_flags_section(Some(&*self.0.clone()), sig, |v| { - v.into_string_parsable(", ", &self.0.config) + v.to_parsable_string(", ", &self.0.config) })) } @@ -73,7 +73,7 @@ impl NuHelpCompleter { let opt_suffix = if let Some(value) = &positional.default_value { format!( " (optional, default: {})", - &value.into_string_parsable(", ", &self.0.config), + &value.to_parsable_string(", ", &self.0.config), ) } else { (" (optional)").to_string() diff --git a/crates/nu-cli/src/menus/menu_completions.rs b/crates/nu-cli/src/menus/menu_completions.rs index 58f0353a3a..0f4814a587 100644 --- a/crates/nu-cli/src/menus/menu_completions.rs +++ b/crates/nu-cli/src/menus/menu_completions.rs @@ -83,10 +83,12 @@ fn convert_to_suggestions( Value::Record { val, .. } => { let text = val .get("value") - .and_then(|val| val.as_string().ok()) + .and_then(|val| val.coerce_string().ok()) .unwrap_or_else(|| "No value key".to_string()); - let description = val.get("description").and_then(|val| val.as_string().ok()); + let description = val + .get("description") + .and_then(|val| val.coerce_string().ok()); let span = match val.get("span") { Some(Value::Record { val: span, .. }) => { diff --git a/crates/nu-cli/src/nu_highlight.rs b/crates/nu-cli/src/nu_highlight.rs index ba533515d2..2c4c221a41 100644 --- a/crates/nu-cli/src/nu_highlight.rs +++ b/crates/nu-cli/src/nu_highlight.rs @@ -45,10 +45,9 @@ impl Command for NuHighlight { }; input.map( - move |x| match x.as_string() { + move |x| match x.coerce_into_string() { Ok(line) => { let highlights = highlighter.highlight(&line, line.len()); - Value::string(highlights.render_simple(), head) } Err(err) => Value::error(err, head), diff --git a/crates/nu-cli/src/reedline_config.rs b/crates/nu-cli/src/reedline_config.rs index e0598edfd9..033e29a773 100644 --- a/crates/nu-cli/src/reedline_config.rs +++ b/crates/nu-cli/src/reedline_config.rs @@ -94,7 +94,7 @@ pub(crate) fn add_menus( if !config .menus .iter() - .any(|menu| menu.name.into_string("", config) == name) + .any(|menu| menu.name.to_expanded_string("", config) == name) { let (block, _) = { let mut working_set = StateWorkingSet::new(&engine_state); @@ -133,7 +133,7 @@ fn add_menu( ) -> Result { let span = menu.menu_type.span(); if let Value::Record { val, .. } = &menu.menu_type { - let layout = extract_value("layout", val, span)?.into_string("", config); + let layout = extract_value("layout", val, span)?.to_expanded_string("", config); match layout.as_str() { "columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config), @@ -142,14 +142,14 @@ fn add_menu( "description" => add_description_menu(line_editor, menu, engine_state, stack, config), _ => Err(ShellError::UnsupportedConfigValue { expected: "columnar, list, ide or description".to_string(), - value: menu.menu_type.into_abbreviated_string(config), + value: menu.menu_type.to_abbreviated_string(config), span: menu.menu_type.span(), }), } } else { Err(ShellError::UnsupportedConfigValue { expected: "only record type".to_string(), - value: menu.menu_type.into_abbreviated_string(config), + value: menu.menu_type.to_abbreviated_string(config), span: menu.menu_type.span(), }) } @@ -181,7 +181,7 @@ pub(crate) fn add_columnar_menu( config: &Config, ) -> Result { let span = menu.menu_type.span(); - let name = menu.name.into_string("", config); + let name = menu.name.to_expanded_string("", config); let mut columnar_menu = ColumnarMenu::default().with_name(&name); if let Value::Record { val, .. } = &menu.menu_type { @@ -254,7 +254,7 @@ pub(crate) fn add_columnar_menu( ); } - let marker = menu.marker.into_string("", config); + let marker = menu.marker.to_expanded_string("", config); columnar_menu = columnar_menu.with_marker(&marker); let only_buffer_difference = menu.only_buffer_difference.as_bool()?; @@ -280,7 +280,7 @@ pub(crate) fn add_columnar_menu( } _ => Err(ShellError::UnsupportedConfigValue { expected: "block or omitted value".to_string(), - value: menu.source.into_abbreviated_string(config), + value: menu.source.to_abbreviated_string(config), span, }), } @@ -294,7 +294,7 @@ pub(crate) fn add_list_menu( stack: &Stack, config: &Config, ) -> Result { - let name = menu.name.into_string("", config); + let name = menu.name.to_expanded_string("", config); let mut list_menu = ListMenu::default().with_name(&name); let span = menu.menu_type.span(); @@ -336,7 +336,7 @@ pub(crate) fn add_list_menu( ); } - let marker = menu.marker.into_string("", config); + let marker = menu.marker.to_expanded_string("", config); list_menu = list_menu.with_marker(&marker); let only_buffer_difference = menu.only_buffer_difference.as_bool()?; @@ -362,7 +362,7 @@ pub(crate) fn add_list_menu( } _ => Err(ShellError::UnsupportedConfigValue { expected: "block or omitted value".to_string(), - value: menu.source.into_abbreviated_string(config), + value: menu.source.to_abbreviated_string(config), span: menu.source.span(), }), } @@ -377,7 +377,7 @@ pub(crate) fn add_ide_menu( config: &Config, ) -> Result { let span = menu.menu_type.span(); - let name = menu.name.into_string("", config); + let name = menu.name.to_expanded_string("", config); let mut ide_menu = IdeMenu::default().with_name(&name); if let Value::Record { val, .. } = &menu.menu_type { @@ -442,7 +442,7 @@ pub(crate) fn add_ide_menu( } else { return Err(ShellError::UnsupportedConfigValue { expected: "bool or record".to_string(), - value: border.into_abbreviated_string(config), + value: border.to_abbreviated_string(config), span: border.span(), }); } @@ -460,7 +460,7 @@ pub(crate) fn add_ide_menu( ide_menu = match extract_value("description_mode", val, span) { Ok(description_mode) => { - let description_mode_str = description_mode.as_string()?; + let description_mode_str = description_mode.coerce_string()?; match description_mode_str.as_str() { "left" => ide_menu.with_description_mode(DescriptionMode::Left), "right" => ide_menu.with_description_mode(DescriptionMode::Right), @@ -468,7 +468,7 @@ pub(crate) fn add_ide_menu( _ => { return Err(ShellError::UnsupportedConfigValue { expected: "\"left\", \"right\" or \"prefer_right\"".to_string(), - value: description_mode.into_abbreviated_string(config), + value: description_mode.to_abbreviated_string(config), span: description_mode.span(), }); } @@ -562,7 +562,7 @@ pub(crate) fn add_ide_menu( ); } - let marker = menu.marker.into_string("", config); + let marker = menu.marker.to_expanded_string("", config); ide_menu = ide_menu.with_marker(&marker); let only_buffer_difference = menu.only_buffer_difference.as_bool()?; @@ -588,7 +588,7 @@ pub(crate) fn add_ide_menu( } _ => Err(ShellError::UnsupportedConfigValue { expected: "block or omitted value".to_string(), - value: menu.source.into_abbreviated_string(config), + value: menu.source.to_abbreviated_string(config), span, }), } @@ -602,7 +602,7 @@ pub(crate) fn add_description_menu( stack: &Stack, config: &Config, ) -> Result { - let name = menu.name.into_string("", config); + let name = menu.name.to_expanded_string("", config); let mut description_menu = DescriptionMenu::default().with_name(&name); let span = menu.menu_type.span(); @@ -676,7 +676,7 @@ pub(crate) fn add_description_menu( ); } - let marker = menu.marker.into_string("", config); + let marker = menu.marker.to_expanded_string("", config); description_menu = description_menu.with_marker(&marker); let only_buffer_difference = menu.only_buffer_difference.as_bool()?; @@ -706,7 +706,7 @@ pub(crate) fn add_description_menu( } _ => Err(ShellError::UnsupportedConfigValue { expected: "closure or omitted value".to_string(), - value: menu.source.into_abbreviated_string(config), + value: menu.source.to_abbreviated_string(config), span: menu.source.span(), }), } @@ -845,7 +845,7 @@ fn add_keybinding( } v => Err(ShellError::UnsupportedConfigValue { expected: "string or list of strings".to_string(), - value: v.into_abbreviated_string(config), + value: v.to_abbreviated_string(config), span: v.span(), }), } @@ -858,7 +858,7 @@ fn add_parsed_keybinding( ) -> Result<(), ShellError> { let modifier = match keybinding .modifier - .into_string("", config) + .to_expanded_string("", config) .to_ascii_lowercase() .as_str() { @@ -875,7 +875,7 @@ fn add_parsed_keybinding( _ => { return Err(ShellError::UnsupportedConfigValue { expected: "CONTROL, SHIFT, ALT or NONE".to_string(), - value: keybinding.modifier.into_abbreviated_string(config), + value: keybinding.modifier.to_abbreviated_string(config), span: keybinding.modifier.span(), }) } @@ -883,7 +883,7 @@ fn add_parsed_keybinding( let keycode = match keybinding .keycode - .into_string("", config) + .to_expanded_string("", config) .to_ascii_lowercase() .as_str() { @@ -936,7 +936,7 @@ fn add_parsed_keybinding( _ => { return Err(ShellError::UnsupportedConfigValue { expected: "crossterm KeyCode".to_string(), - value: keybinding.keycode.into_abbreviated_string(config), + value: keybinding.keycode.to_abbreviated_string(config), span: keybinding.keycode.span(), }) } @@ -974,7 +974,10 @@ fn parse_event(value: &Value, config: &Config) -> Result, match value { Value::Record { val: record, .. } => match EventType::try_from_record(record, span)? { EventType::Send(value) => event_from_record( - value.into_string("", config).to_ascii_lowercase().as_str(), + value + .to_expanded_string("", config) + .to_ascii_lowercase() + .as_str(), record, config, span, @@ -982,7 +985,10 @@ fn parse_event(value: &Value, config: &Config) -> Result, .map(Some), EventType::Edit(value) => { let edit = edit_from_record( - value.into_string("", config).to_ascii_lowercase().as_str(), + value + .to_expanded_string("", config) + .to_ascii_lowercase() + .as_str(), record, config, span, @@ -1010,7 +1016,7 @@ fn parse_event(value: &Value, config: &Config) -> Result, } v => Err(ShellError::UnsupportedConfigValue { expected: "list of events".to_string(), - value: v.into_abbreviated_string(config), + value: v.to_abbreviated_string(config), span: v.span(), }), }, @@ -1036,7 +1042,7 @@ fn parse_event(value: &Value, config: &Config) -> Result, Value::Nothing { .. } => Ok(None), v => Err(ShellError::UnsupportedConfigValue { expected: "record or list of records, null to unbind key".to_string(), - value: v.into_abbreviated_string(config), + value: v.to_abbreviated_string(config), span: v.span(), }), } @@ -1079,11 +1085,11 @@ fn event_from_record( "openeditor" => ReedlineEvent::OpenEditor, "menu" => { let menu = extract_value("name", record, span)?; - ReedlineEvent::Menu(menu.into_string("", config)) + ReedlineEvent::Menu(menu.to_expanded_string("", config)) } "executehostcommand" => { let cmd = extract_value("cmd", record, span)?; - ReedlineEvent::ExecuteHostCommand(cmd.into_string("", config)) + ReedlineEvent::ExecuteHostCommand(cmd.to_expanded_string("", config)) } v => { return Err(ShellError::UnsupportedConfigValue { @@ -1188,7 +1194,7 @@ fn edit_from_record( } "insertstring" => { let value = extract_value("value", record, span)?; - EditCommand::InsertString(value.into_string("", config)) + EditCommand::InsertString(value.to_expanded_string("", config)) } "insertnewline" => EditCommand::InsertNewline, "backspace" => EditCommand::Backspace, @@ -1289,7 +1295,7 @@ fn edit_from_record( fn extract_char(value: &Value, config: &Config) -> Result { let span = value.span(); value - .into_string("", config) + .to_expanded_string("", config) .chars() .next() .ok_or_else(|| ShellError::MissingConfigValue { diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs index b2a87eb87d..a6c2aff1c5 100644 --- a/crates/nu-cli/src/repl.rs +++ b/crates/nu-cli/src/repl.rs @@ -638,9 +638,7 @@ fn do_auto_cd( let shells = stack.get_env_var(engine_state, "NUSHELL_SHELLS"); let mut shells = if let Some(v) = shells { - v.as_list() - .map(|x| x.to_vec()) - .unwrap_or_else(|_| vec![cwd]) + v.into_list().unwrap_or_else(|_| vec![cwd]) } else { vec![cwd] }; @@ -707,7 +705,7 @@ fn do_run_cmd( if shell_integration { if let Some(cwd) = stack.get_env_var(engine_state, "PWD") { - let path = cwd.as_string()?; + let path = cwd.coerce_into_string()?; // Try to abbreviate string for windows title let maybe_abbrev_path = if let Some(p) = nu_path::home_dir() { @@ -746,7 +744,7 @@ fn do_shell_integration_finalize_command( ) -> Result<()> { run_ansi_sequence(&get_command_finished_marker(stack, engine_state))?; if let Some(cwd) = stack.get_env_var(engine_state, "PWD") { - let path = cwd.as_string()?; + let path = cwd.coerce_into_string()?; // Supported escape sequences of Microsoft's Visual Studio Code (vscode) // https://code.visualstudio.com/docs/terminal/shell-integration#_supported-escape-sequences diff --git a/crates/nu-cmd-base/src/hook.rs b/crates/nu-cmd-base/src/hook.rs index d3893e006a..518f00b173 100644 --- a/crates/nu-cmd-base/src/hook.rs +++ b/crates/nu-cmd-base/src/hook.rs @@ -150,7 +150,7 @@ pub fn eval_hook( // If it returns true (the default if a condition block is not specified), the hook should be run. let do_run_hook = if let Some(condition) = val.get("condition") { let other_span = condition.span(); - if let Ok(block_id) = condition.as_block() { + if let Ok(block_id) = condition.coerce_block() { match run_hook_block( engine_state, stack, diff --git a/crates/nu-cmd-base/src/util.rs b/crates/nu-cmd-base/src/util.rs index d7cf497e05..120b6feae5 100644 --- a/crates/nu-cmd-base/src/util.rs +++ b/crates/nu-cmd-base/src/util.rs @@ -66,7 +66,7 @@ fn get_editor_commandline( match value { Value::String { val, .. } if !val.is_empty() => Ok((val.to_string(), Vec::new())), Value::List { vals, .. } if !vals.is_empty() => { - let mut editor_cmd = vals.iter().map(|l| l.as_string()); + let mut editor_cmd = vals.iter().map(|l| l.coerce_string()); match editor_cmd.next().transpose()? { Some(editor) if !editor.is_empty() => { let params = editor_cmd.collect::>()?; diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/conversion.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/conversion.rs index 1fb12c627e..bc70db8d60 100644 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/conversion.rs +++ b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/conversion.rs @@ -342,7 +342,7 @@ fn typed_column_to_series(name: &str, column: TypedColumn) -> Result { let series_values: Result, _> = - column.values.iter().map(|v| v.as_string()).collect(); + column.values.iter().map(|v| v.coerce_string()).collect(); Ok(Series::new(name, series_values?)) } DataType::Object(_, _) => value_to_series(name, &column.values), @@ -561,7 +561,7 @@ fn input_type_list_to_series( let value_list = v .as_list()? .iter() - .map(|v| v.as_string()) + .map(|v| v.coerce_string()) .collect::, _>>() .map_err(inconsistent_error)?; builder.append_values_iter(value_list.iter().map(AsRef::as_ref)); diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_schema.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_schema.rs index f7ae2736ac..ed02acdfa8 100644 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_schema.rs +++ b/crates/nu-cmd-dataframe/src/dataframe/values/nu_schema.rs @@ -73,7 +73,7 @@ fn value_to_fields(value: &Value, span: Span) -> Result, ShellError> Ok(Field::new(col, dtype)) } _ => { - let dtype = str_to_dtype(&val.as_string()?, span)?; + let dtype = str_to_dtype(&val.coerce_string()?, span)?; Ok(Field::new(col, dtype)) } }) diff --git a/crates/nu-cmd-extra/src/extra/filters/update_cells.rs b/crates/nu-cmd-extra/src/extra/filters/update_cells.rs index 22b16cddfb..0b05873320 100644 --- a/crates/nu-cmd-extra/src/extra/filters/update_cells.rs +++ b/crates/nu-cmd-extra/src/extra/filters/update_cells.rs @@ -6,7 +6,6 @@ use nu_protocol::{ PipelineIterator, ShellError, Signature, Span, SyntaxShape, Type, Value, }; use std::collections::HashSet; -use std::iter::FromIterator; #[derive(Clone)] pub struct UpdateCells; @@ -114,14 +113,12 @@ impl Command for UpdateCells { // the columns to update let columns: Option = call.get_flag(&engine_state, &mut stack, "columns")?; let columns: Option> = match columns { - Some(val) => { - let cols = val - .as_list()? - .iter() - .map(|val| val.as_string()) - .collect::, ShellError>>()?; - Some(HashSet::from_iter(cols)) - } + Some(val) => Some( + val.into_list()? + .into_iter() + .map(Value::coerce_into_string) + .collect::, ShellError>>()?, + ), None => None, }; diff --git a/crates/nu-cmd-extra/src/extra/formats/to/html.rs b/crates/nu-cmd-extra/src/extra/formats/to/html.rs index 82d61c4527..cd879e6fa9 100644 --- a/crates/nu-cmd-extra/src/extra/formats/to/html.rs +++ b/crates/nu-cmd-extra/src/extra/formats/to/html.rs @@ -432,7 +432,7 @@ fn html_value(value: Value, config: &Config) -> String { output_string.push_str(""); } other => output_string.push_str( - &v_htmlescape::escape(&other.into_abbreviated_string(config)) + &v_htmlescape::escape(&other.to_abbreviated_string(config)) .to_string() .replace('\n', "
"), ), diff --git a/crates/nu-cmd-extra/src/extra/platform/ansi/gradient.rs b/crates/nu-cmd-extra/src/extra/platform/ansi/gradient.rs index 325dc085f4..53d51b0d93 100644 --- a/crates/nu-cmd-extra/src/extra/platform/ansi/gradient.rs +++ b/crates/nu-cmd-extra/src/extra/platform/ansi/gradient.rs @@ -104,7 +104,7 @@ impl Command for SubCommand { fn value_to_color(v: Option) -> Result, ShellError> { let s = match v { None => return Ok(None), - Some(x) => x.as_string()?, + Some(x) => x.coerce_into_string()?, }; Ok(Some(Rgb::from_hex_string(s))) } diff --git a/crates/nu-cmd-extra/src/extra/strings/format/command.rs b/crates/nu-cmd-extra/src/extra/strings/format/command.rs index d7413073ce..6bba76c776 100644 --- a/crates/nu-cmd-extra/src/extra/strings/format/command.rs +++ b/crates/nu-cmd-extra/src/extra/strings/format/command.rs @@ -54,8 +54,8 @@ impl Command for FormatPattern { match specified_pattern { Err(e) => Err(e), Ok(pattern) => { - let string_pattern = pattern.as_string()?; let string_span = pattern.span(); + let string_pattern = pattern.coerce_into_string()?; // the string span is start as `"`, we don't need the character // to generate proper span for sub expression. let ops = extract_formatting_operations( @@ -287,7 +287,7 @@ fn format_record( .collect(); match data_as_value.clone().follow_cell_path(&path_members, false) { Ok(value_at_column) => { - output.push_str(value_at_column.into_string(", ", config).as_str()) + output.push_str(value_at_column.to_expanded_string(", ", config).as_str()) } Err(se) => return Err(se), } @@ -298,7 +298,7 @@ fn format_record( None => { let parsed_result = eval_expression(engine_state, stack, &exp); if let Ok(val) = parsed_result { - output.push_str(&val.into_abbreviated_string(config)) + output.push_str(&val.to_abbreviated_string(config)) } } Some(err) => { diff --git a/crates/nu-color-config/src/matching_brackets_style.rs b/crates/nu-color-config/src/matching_brackets_style.rs index b9389db800..4e6672e339 100644 --- a/crates/nu-color-config/src/matching_brackets_style.rs +++ b/crates/nu-color-config/src/matching_brackets_style.rs @@ -6,7 +6,7 @@ pub fn get_matching_brackets_style(default_style: Style, conf: &Config) -> Style const MATCHING_BRACKETS_CONFIG_KEY: &str = "shape_matching_brackets"; match conf.color_config.get(MATCHING_BRACKETS_CONFIG_KEY) { - Some(int_color) => match int_color.as_string() { + Some(int_color) => match int_color.coerce_string() { Ok(int_color) => merge_styles(default_style, lookup_ansi_color_style(&int_color)), Err(_) => default_style, }, diff --git a/crates/nu-color-config/src/nu_style.rs b/crates/nu-color-config/src/nu_style.rs index a7a2a4a347..18f1538762 100644 --- a/crates/nu-color-config/src/nu_style.rs +++ b/crates/nu-color-config/src/nu_style.rs @@ -104,7 +104,7 @@ pub fn color_record_to_nustyle(value: &Value) -> Style { for (k, v) in record { // Because config already type-checked the color_config records, this doesn't bother giving errors // if there are unrecognised keys or bad values. - if let Ok(v) = v.as_string() { + if let Ok(v) = v.coerce_string() { match k.as_str() { "fg" => fg = Some(v), diff --git a/crates/nu-command/src/charting/histogram.rs b/crates/nu-command/src/charting/histogram.rs index b46f1b8a8e..c756af86f2 100755 --- a/crates/nu-command/src/charting/histogram.rs +++ b/crates/nu-command/src/charting/histogram.rs @@ -127,15 +127,16 @@ impl Command for Histogram { let span = call.head; let data_as_value = input.into_value(span); + let value_span = data_as_value.span(); // `input` is not a list, here we can return an error. run_histogram( - data_as_value.as_list()?.to_vec(), + data_as_value.into_list()?, column_name, frequency_column_name, calc_method, span, // Note that as_list() filters out Value::Error here. - data_as_value.span(), + value_span, ) } } diff --git a/crates/nu-command/src/conversions/into/datetime.rs b/crates/nu-command/src/conversions/into/datetime.rs index 057a8f1e73..96b0f226ee 100644 --- a/crates/nu-command/src/conversions/into/datetime.rs +++ b/crates/nu-command/src/conversions/into/datetime.rs @@ -261,11 +261,12 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value { // Let's try dtparse first if matches!(input, Value::String { .. }) && dateformat.is_none() { - if let Ok(input_val) = input.as_spanned_string() { - match parse_date_from_string(&input_val.item, input_val.span) { - Ok(date) => return Value::date(date, input_val.span), + let span = input.span(); + if let Ok(input_val) = input.coerce_string() { + match parse_date_from_string(&input_val, span) { + Ok(date) => return Value::date(date, span), Err(_) => { - if let Ok(date) = from_human_time(&input_val.item) { + if let Ok(date) = from_human_time(&input_val) { match date { ParseResult::Date(date) => { let time = NaiveTime::from_hms_opt(0, 0, 0).expect("valid time"); @@ -274,10 +275,10 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value { combined, *Local::now().offset(), ); - return Value::date(dt_fixed, input_val.span); + return Value::date(dt_fixed, span); } ParseResult::DateTime(date) => { - return Value::date(date.fixed_offset(), input_val.span) + return Value::date(date.fixed_offset(), span) } ParseResult::Time(time) => { let date = Local::now().date_naive(); @@ -286,7 +287,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value { combined, *Local::now().offset(), ); - return Value::date(dt_fixed, input_val.span); + return Value::date(dt_fixed, span); } } } @@ -338,7 +339,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value { } None => Value::error( ShellError::DatetimeParseError { - msg: input.debug_value(), + msg: input.to_debug_string(), span: *span, }, *span, @@ -351,7 +352,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value { } None => Value::error( ShellError::DatetimeParseError { - msg: input.debug_value(), + msg: input.to_debug_string(), span: *span, }, *span, diff --git a/crates/nu-command/src/conversions/into/string.rs b/crates/nu-command/src/conversions/into/string.rs index dba93c0d6a..0fc5d06adb 100644 --- a/crates/nu-command/src/conversions/into/string.rs +++ b/crates/nu-command/src/conversions/into/string.rs @@ -203,8 +203,10 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value { Value::Date { val, .. } => Value::string(val.format("%c").to_string(), span), Value::String { val, .. } => Value::string(val.to_string(), span), - Value::Filesize { val: _, .. } => Value::string(input.into_string(", ", config), span), - Value::Duration { val: _, .. } => Value::string(input.into_string("", config), span), + Value::Filesize { val: _, .. } => { + Value::string(input.to_expanded_string(", ", config), span) + } + Value::Duration { val: _, .. } => Value::string(input.to_expanded_string("", config), span), Value::Error { error, .. } => Value::string(into_code(error).unwrap_or_default(), span), Value::Nothing { .. } => Value::string("".to_string(), span), diff --git a/crates/nu-command/src/conversions/into/value.rs b/crates/nu-command/src/conversions/into/value.rs index 0a2414eba7..3771b0c701 100644 --- a/crates/nu-command/src/conversions/into/value.rs +++ b/crates/nu-command/src/conversions/into/value.rs @@ -8,7 +8,7 @@ use nu_protocol::{ }; use once_cell::sync::Lazy; use regex::{Regex, RegexBuilder}; -use std::{collections::HashSet, iter::FromIterator}; +use std::collections::HashSet; #[derive(Clone)] pub struct IntoValue; @@ -71,14 +71,12 @@ impl Command for IntoValue { // the columns to update let columns: Option = call.get_flag(&engine_state, stack, "columns")?; let columns: Option> = match columns { - Some(val) => { - let cols = val - .as_list()? - .iter() - .map(|val| val.as_string()) - .collect::, ShellError>>()?; - Some(HashSet::from_iter(cols)) - } + Some(val) => Some( + val.into_list()? + .into_iter() + .map(Value::coerce_into_string) + .collect::, ShellError>>()?, + ), None => None, }; @@ -144,7 +142,7 @@ impl Iterator for UpdateCellIterator { // for a particular datatype. If it does, it will convert the cell to that datatype. fn process_cell(val: Value, display_as_filesizes: bool, span: Span) -> Result { // step 1: convert value to string - let val_str = val.as_string().unwrap_or_default(); + let val_str = val.coerce_string().unwrap_or_default(); // step 2: bounce string up against regexes if BOOLEAN_RE.is_match(&val_str) { diff --git a/crates/nu-command/src/date/humanize.rs b/crates/nu-command/src/date/humanize.rs index 5e74c02c00..b46f516e3c 100644 --- a/crates/nu-command/src/date/humanize.rs +++ b/crates/nu-command/src/date/humanize.rs @@ -80,7 +80,7 @@ fn helper(value: Value, head: Span) -> Value { Value::Date { val, .. } => Value::string(humanize_date(val), head), _ => Value::error( ShellError::DatetimeParseError { - msg: value.debug_value(), + msg: value.to_debug_string(), span: head, }, head, diff --git a/crates/nu-command/src/date/to_record.rs b/crates/nu-command/src/date/to_record.rs index b14c13eef9..31b2cf138e 100644 --- a/crates/nu-command/src/date/to_record.rs +++ b/crates/nu-command/src/date/to_record.rs @@ -123,7 +123,7 @@ fn helper(val: Value, head: Span) -> Value { Value::Date { val, .. } => parse_date_into_table(val, head), _ => Value::error( DatetimeParseError { - msg: val.debug_value(), + msg: val.to_debug_string(), span: head, }, head, diff --git a/crates/nu-command/src/date/to_table.rs b/crates/nu-command/src/date/to_table.rs index 84481509a5..1a0930c021 100644 --- a/crates/nu-command/src/date/to_table.rs +++ b/crates/nu-command/src/date/to_table.rs @@ -122,7 +122,7 @@ fn helper(val: Value, head: Span) -> Value { Value::Date { val, .. } => parse_date_into_table(val, head), _ => Value::error( DatetimeParseError { - msg: val.debug_value(), + msg: val.to_debug_string(), span: head, }, head, diff --git a/crates/nu-command/src/date/to_timezone.rs b/crates/nu-command/src/date/to_timezone.rs index 9414e729e0..b5886ea488 100644 --- a/crates/nu-command/src/date/to_timezone.rs +++ b/crates/nu-command/src/date/to_timezone.rs @@ -123,7 +123,7 @@ fn helper(value: Value, head: Span, timezone: &Spanned) -> Value { } _ => Value::error( ShellError::DatetimeParseError { - msg: value.debug_value(), + msg: value.to_debug_string(), span: head, }, head, diff --git a/crates/nu-command/src/debug/debug_.rs b/crates/nu-command/src/debug/debug_.rs index dc08c9ff4c..ffd6bc90d7 100644 --- a/crates/nu-command/src/debug/debug_.rs +++ b/crates/nu-command/src/debug/debug_.rs @@ -44,9 +44,9 @@ impl Command for Debug { input.map( move |x| { if raw { - Value::string(x.debug_value(), head) + Value::string(x.to_debug_string(), head) } else { - Value::string(x.debug_string(", ", &config), head) + Value::string(x.to_expanded_string(", ", &config), head) } }, engine_state.ctrlc.clone(), diff --git a/crates/nu-command/src/debug/view_source.rs b/crates/nu-command/src/debug/view_source.rs index 400584f93e..26a4d440e2 100644 --- a/crates/nu-command/src/debug/view_source.rs +++ b/crates/nu-command/src/debug/view_source.rs @@ -129,7 +129,7 @@ impl Command for ViewSource { } } value => { - if let Ok(block_id) = value.as_block() { + if let Ok(block_id) = value.coerce_block() { let block = engine_state.get_block(block_id); if let Some(span) = block.span { diff --git a/crates/nu-command/src/env/load_env.rs b/crates/nu-command/src/env/load_env.rs index a9a859cc05..66f995e9ef 100644 --- a/crates/nu-command/src/env/load_env.rs +++ b/crates/nu-command/src/env/load_env.rs @@ -69,7 +69,7 @@ impl Command for LoadEnv { if env_var == "PWD" { let cwd = current_dir(engine_state, stack)?; - let rhs = rhs.as_string()?; + let rhs = rhs.coerce_into_string()?; let rhs = nu_path::expand_path_with(rhs, cwd); stack.add_env_var( env_var, diff --git a/crates/nu-command/src/env/with_env.rs b/crates/nu-command/src/env/with_env.rs index 336f630a8e..1c7a621251 100644 --- a/crates/nu-command/src/env/with_env.rs +++ b/crates/nu-command/src/env/with_env.rs @@ -115,7 +115,7 @@ fn with_env( // primitive values([X Y W Z]) for row in table.chunks(2) { if row.len() == 2 { - env.insert(row[0].as_string()?, row[1].clone()); + env.insert(row[0].coerce_string()?, row[1].clone()); } // TODO: else error? } diff --git a/crates/nu-command/src/filesystem/cd.rs b/crates/nu-command/src/filesystem/cd.rs index 40256cce2d..b12611dbfe 100644 --- a/crates/nu-command/src/filesystem/cd.rs +++ b/crates/nu-command/src/filesystem/cd.rs @@ -79,7 +79,7 @@ impl Command for Cd { let oldpwd = stack.get_env_var(engine_state, "OLDPWD"); if let Some(oldpwd) = oldpwd { - let path = oldpwd.as_path()?; + let path = oldpwd.to_path()?; let path = match nu_path::canonicalize_with(path.clone(), &cwd) { Ok(p) => p, Err(_) => { diff --git a/crates/nu-command/src/filesystem/open.rs b/crates/nu-command/src/filesystem/open.rs index 21989e8e3d..da77c3c83a 100644 --- a/crates/nu-command/src/filesystem/open.rs +++ b/crates/nu-command/src/filesystem/open.rs @@ -62,8 +62,11 @@ impl Command for Open { if paths.is_empty() && call.rest_iter(0).next().is_none() { // try to use path from pipeline input if there were no positional or spread args - let filename = match input { - PipelineData::Value(val, ..) => val.as_spanned_string()?, + let (filename, span) = match input { + PipelineData::Value(val, ..) => { + let span = val.span(); + (val.coerce_into_string()?, span) + } _ => { return Err(ShellError::MissingParameter { param_name: "needs filename".to_string(), @@ -73,8 +76,8 @@ impl Command for Open { }; paths.push(Spanned { - item: NuPath::UnQuoted(filename.item), - span: filename.span, + item: NuPath::UnQuoted(filename), + span, }); } diff --git a/crates/nu-command/src/filesystem/save.rs b/crates/nu-command/src/filesystem/save.rs index 555aa0f5bd..129faae1c7 100644 --- a/crates/nu-command/src/filesystem/save.rs +++ b/crates/nu-command/src/filesystem/save.rs @@ -332,7 +332,7 @@ fn value_to_bytes(value: Value) -> Result, ShellError> { Value::List { vals, .. } => { let val = vals .into_iter() - .map(|it| it.as_string()) + .map(Value::coerce_into_string) .collect::, ShellError>>()? .join("\n") + "\n"; @@ -341,7 +341,7 @@ fn value_to_bytes(value: Value) -> Result, ShellError> { } // Propagate errors by explicitly matching them before the final case. Value::Error { error, .. } => Err(*error), - other => Ok(other.as_string()?.into_bytes()), + other => Ok(other.coerce_into_string()?.into_bytes()), } } diff --git a/crates/nu-command/src/filters/find.rs b/crates/nu-command/src/filters/find.rs index 32a68c19e9..8c84b322b2 100644 --- a/crates/nu-command/src/filters/find.rs +++ b/crates/nu-command/src/filters/find.rs @@ -271,7 +271,7 @@ where I: IntoIterator, { values.into_iter().any(|v| { - re.is_match(v.into_string(" ", config).as_str()) + re.is_match(v.to_expanded_string(" ", config).as_str()) .unwrap_or(false) }) } @@ -284,13 +284,13 @@ fn highlight_terms_in_string( string_style: Style, highlight_style: Style, ) -> Value { - let val_str = val.into_string("", config); + let val_str = val.to_expanded_string("", config); if let Some(term) = terms .iter() - .find(|term| contains_ignore_case(&val_str, &term.into_string("", config))) + .find(|term| contains_ignore_case(&val_str, &term.to_expanded_string("", config))) { - let term_str = term.into_string("", config); + let term_str = term.to_expanded_string("", config); let highlighted_str = highlight_search_string(&val_str, &term_str, &string_style, &highlight_style) .unwrap_or_else(|_| string_style.paint(&term_str).to_string()); @@ -312,7 +312,10 @@ fn highlight_terms_in_record_with_search_columns( highlight_style: Style, ) -> Value { let col_select = !search_cols.is_empty(); - let term_strs: Vec<_> = terms.iter().map(|v| v.into_string("", config)).collect(); + let term_strs: Vec<_> = terms + .iter() + .map(|v| v.to_expanded_string("", config)) + .collect(); // TODO: change API to mutate in place let mut record = record.clone(); @@ -321,7 +324,7 @@ fn highlight_terms_in_record_with_search_columns( if col_select && !search_cols.contains(col) { continue; } - let val_str = val.into_string("", config); + let val_str = val.to_expanded_string("", config); let Some(term_str) = term_strs .iter() .find(|term_str| contains_ignore_case(&val_str, term_str)) @@ -360,7 +363,7 @@ fn find_with_rest_and_highlight( let terms = call.rest::(&engine_state, stack, 0)?; let lower_terms = terms .iter() - .map(|v| Value::string(v.into_string("", &config).to_lowercase(), span)) + .map(|v| Value::string(v.to_expanded_string("", &config).to_lowercase(), span)) .collect::>(); let style_computer = StyleComputer::from_config(&engine_state, stack); @@ -466,11 +469,11 @@ fn find_with_rest_and_highlight( for line in val.split(split_char) { for term in lower_terms.iter() { - let term_str = term.into_string("", &filter_config); + let term_str = term.to_expanded_string("", &filter_config); let lower_val = line.to_lowercase(); - if lower_val - .contains(&term.into_string("", &config).to_lowercase()) - { + if lower_val.contains( + &term.to_expanded_string("", &config).to_lowercase(), + ) { output.push(Value::string( highlight_search_string( line, @@ -513,7 +516,10 @@ fn value_should_be_printed( columns_to_search: &[String], invert: bool, ) -> bool { - let lower_value = Value::string(value.into_string("", filter_config).to_lowercase(), span); + let lower_value = Value::string( + value.to_expanded_string("", filter_config).to_lowercase(), + span, + ); let mut match_found = lower_terms.iter().any(|term| match value { Value::Bool { .. } @@ -577,7 +583,7 @@ fn record_matches_term( } let lower_val = if !val.is_error() { Value::string( - val.into_string("", filter_config).to_lowercase(), + val.to_expanded_string("", filter_config).to_lowercase(), Span::test_data(), ) } else { diff --git a/crates/nu-command/src/filters/flatten.rs b/crates/nu-command/src/filters/flatten.rs index 76bad8e5a4..372f60d6e0 100644 --- a/crates/nu-command/src/filters/flatten.rs +++ b/crates/nu-command/src/filters/flatten.rs @@ -201,13 +201,7 @@ fn flat_value(columns: &[CellPath], item: Value, all: bool) -> Vec { if need_flatten { let records = vals .into_iter() - .filter_map(|v| { - if let Value::Record { val, .. } = v { - Some(val) - } else { - None - } - }) + .filter_map(|v| v.into_record().ok()) .collect(); inner_table = Some(TableInside::FlattenedRows { diff --git a/crates/nu-command/src/filters/group_by.rs b/crates/nu-command/src/filters/group_by.rs index 0dfb9a4636..bbf32f4c6f 100644 --- a/crates/nu-command/src/filters/group_by.rs +++ b/crates/nu-command/src/filters/group_by.rs @@ -208,7 +208,7 @@ pub fn group_cell_path( continue; // likely the result of a failed optional access, ignore this value } - let group_key = group_key.as_string()?; + let group_key = group_key.coerce_string()?; let group = groups.entry(group_key).or_default(); group.push(value); } @@ -220,7 +220,7 @@ pub fn group_no_grouper(values: Vec) -> Result> = IndexMap::new(); for value in values.into_iter() { - let group_key = value.as_string()?; + let group_key = value.coerce_string()?; let group = groups.entry(group_key).or_default(); group.push(value); } @@ -259,7 +259,7 @@ fn group_closure( let key = match s.next() { Some(Value::Error { .. }) | None => error_key.into(), - Some(return_value) => return_value.as_string()?, + Some(return_value) => return_value.coerce_into_string()?, }; if s.next().is_some() { diff --git a/crates/nu-command/src/filters/headers.rs b/crates/nu-command/src/filters/headers.rs index 2f0eaf1838..4d8927716f 100644 --- a/crates/nu-command/src/filters/headers.rs +++ b/crates/nu-command/src/filters/headers.rs @@ -116,7 +116,7 @@ fn extract_headers( .values() .enumerate() .map(|(idx, value)| { - let col = value.into_string("", config); + let col = value.to_expanded_string("", config); if col.is_empty() { format!("column{idx}") } else { diff --git a/crates/nu-command/src/filters/insert.rs b/crates/nu-command/src/filters/insert.rs index b760c0a4e7..4a903f2faa 100644 --- a/crates/nu-command/src/filters/insert.rs +++ b/crates/nu-command/src/filters/insert.rs @@ -136,7 +136,7 @@ fn insert( match input { PipelineData::Value(mut value, metadata) => { - if replacement.as_block().is_ok() { + if replacement.coerce_block().is_ok() { match (cell_path.members.first(), &mut value) { (Some(PathMember::String { .. }), Value::List { vals, .. }) => { let span = replacement.span(); @@ -200,7 +200,7 @@ fn insert( } if path.is_empty() { - if replacement.as_block().is_ok() { + if replacement.coerce_block().is_ok() { let span = replacement.span(); let value = stream.next(); let end_of_stream = value.is_none(); @@ -232,7 +232,7 @@ fn insert( pre_elems.push(replacement); } } else if let Some(mut value) = stream.next() { - if replacement.as_block().is_ok() { + if replacement.coerce_block().is_ok() { insert_single_value_by_closure( &mut value, replacement, @@ -258,7 +258,7 @@ fn insert( .into_iter() .chain(stream) .into_pipeline_data_with_metadata(metadata, ctrlc)) - } else if replacement.as_block().is_ok() { + } else if replacement.coerce_block().is_ok() { let engine_state = engine_state.clone(); let replacement_span = replacement.span(); let capture_block = Closure::from_value(replacement)?; diff --git a/crates/nu-command/src/filters/join.rs b/crates/nu-command/src/filters/join.rs index 471f50595d..565d5910b7 100644 --- a/crates/nu-command/src/filters/join.rs +++ b/crates/nu-command/src/filters/join.rs @@ -264,7 +264,7 @@ fn join_rows( } = this_row { if let Some(this_valkey) = this_record.get(this_join_key) { - if let Some(other_rows) = other.get(&this_valkey.into_string(sep, config)) { + if let Some(other_rows) = other.get(&this_valkey.to_expanded_string(sep, config)) { if matches!(include_inner, IncludeInner::Yes) { for other_record in other_rows { // `other` table contains rows matching `this` row on the join column @@ -346,7 +346,7 @@ fn lookup_table<'a>( for row in rows { if let Value::Record { val: record, .. } = row { if let Some(val) = record.get(on) { - let valkey = val.into_string(sep, config); + let valkey = val.to_expanded_string(sep, config); map.entry(valkey).or_default().push(record); } }; diff --git a/crates/nu-command/src/filters/move_.rs b/crates/nu-command/src/filters/move_.rs index aba70e7ed4..dd582a7fc6 100644 --- a/crates/nu-command/src/filters/move_.rs +++ b/crates/nu-command/src/filters/move_.rs @@ -121,12 +121,12 @@ impl Command for Move { let before_or_after = match (after, before) { (Some(v), None) => Spanned { - item: BeforeOrAfter::After(v.as_string()?), span: v.span(), + item: BeforeOrAfter::After(v.coerce_into_string()?), }, (None, Some(v)) => Spanned { - item: BeforeOrAfter::Before(v.as_string()?), span: v.span(), + item: BeforeOrAfter::Before(v.coerce_into_string()?), }, (Some(_), Some(_)) => { return Err(ShellError::GenericError { @@ -222,7 +222,7 @@ fn move_record_columns( // Find indices of columns to be moved for column in columns.iter() { - let column_str = column.as_string()?; + let column_str = column.coerce_string()?; if let Some(idx) = record.index_of(&column_str) { column_idx.push(idx); diff --git a/crates/nu-command/src/filters/sort.rs b/crates/nu-command/src/filters/sort.rs index 1eb5fdfdc7..5ddf278af4 100644 --- a/crates/nu-command/src/filters/sort.rs +++ b/crates/nu-command/src/filters/sort.rs @@ -193,7 +193,7 @@ fn sort_record( match &a.1 { Value::String { val, .. } => val.clone(), val => { - if let Ok(val) = val.as_string() { + if let Ok(val) = val.coerce_string() { val } else { // Values that can't be turned to strings are disregarded by the sort @@ -209,7 +209,7 @@ fn sort_record( match &b.1 { Value::String { val, .. } => val.clone(), val => { - if let Ok(val) = val.as_string() { + if let Ok(val) = val.coerce_string() { val } else { // Values that can't be turned to strings are disregarded by the sort @@ -275,7 +275,10 @@ pub fn sort( }; if natural { - match (folded_left.as_string(), folded_right.as_string()) { + match ( + folded_left.coerce_into_string(), + folded_right.coerce_into_string(), + ) { (Ok(left), Ok(right)) => compare_str(left, right), _ => Ordering::Equal, } @@ -285,7 +288,7 @@ pub fn sort( .unwrap_or(Ordering::Equal) } } else if natural { - match (a.as_string(), b.as_string()) { + match (a.coerce_string(), b.coerce_string()) { (Ok(left), Ok(right)) => compare_str(left, right), _ => Ordering::Equal, } @@ -334,7 +337,10 @@ pub fn process( _ => right_res, }; if natural { - match (folded_left.as_string(), folded_right.as_string()) { + match ( + folded_left.coerce_into_string(), + folded_right.coerce_into_string(), + ) { (Ok(left), Ok(right)) => compare_str(left, right), _ => Ordering::Equal, } diff --git a/crates/nu-command/src/filters/split_by.rs b/crates/nu-command/src/filters/split_by.rs index 177c0d787e..6686d9ea1f 100644 --- a/crates/nu-command/src/filters/split_by.rs +++ b/crates/nu-command/src/filters/split_by.rs @@ -96,7 +96,7 @@ pub fn split_by( match splitter { Some(v) => { let splitter = Some(Spanned { - item: v.as_string()?, + item: v.coerce_into_string()?, span: name, }); Ok(split(splitter.as_ref(), input, name)?) @@ -133,7 +133,7 @@ pub fn split( }; match group_key { - Some(group_key) => Ok(group_key.as_string()?), + Some(group_key) => Ok(group_key.coerce_string()?), None => Err(ShellError::CantFindColumn { col_name: column_name.item.to_string(), span: column_name.span, @@ -145,7 +145,7 @@ pub fn split( data_split(values, Some(&block), span) } Grouper::ByColumn(None) => { - let block = move |_, row: &Value| row.as_string(); + let block = move |_, row: &Value| row.coerce_string(); data_split(values, Some(&block), span) } @@ -164,7 +164,7 @@ fn data_group( let group_key = if let Some(ref grouper) = grouper { grouper(idx, &value) } else { - value.as_string() + value.coerce_string() }; let group = groups.entry(group_key?).or_default(); diff --git a/crates/nu-command/src/filters/transpose.rs b/crates/nu-command/src/filters/transpose.rs index e407e4e1c4..85f372b676 100644 --- a/crates/nu-command/src/filters/transpose.rs +++ b/crates/nu-command/src/filters/transpose.rs @@ -193,7 +193,7 @@ pub fn transpose( if let Some(desc) = descs.first() { match &i.get_data_by_key(desc) { Some(x) => { - if let Ok(s) = x.as_string() { + if let Ok(s) = x.coerce_string() { headers.push(s.to_string()); } else { return Err(ShellError::GenericError { diff --git a/crates/nu-command/src/filters/update.rs b/crates/nu-command/src/filters/update.rs index 4d5283a1d1..083cf11bf1 100644 --- a/crates/nu-command/src/filters/update.rs +++ b/crates/nu-command/src/filters/update.rs @@ -118,7 +118,7 @@ fn update( match input { PipelineData::Value(mut value, metadata) => { - if replacement.as_block().is_ok() { + if replacement.coerce_block().is_ok() { match (cell_path.members.first(), &mut value) { (Some(PathMember::String { .. }), Value::List { vals, .. }) => { let span = replacement.span(); @@ -186,7 +186,7 @@ fn update( // cannot fail since loop above does at least one iteration or returns an error let value = pre_elems.last_mut().expect("one element"); - if replacement.as_block().is_ok() { + if replacement.coerce_block().is_ok() { update_single_value_by_closure( value, replacement, @@ -205,7 +205,7 @@ fn update( .into_iter() .chain(stream) .into_pipeline_data_with_metadata(metadata, ctrlc)) - } else if replacement.as_block().is_ok() { + } else if replacement.coerce_block().is_ok() { let replacement_span = replacement.span(); let engine_state = engine_state.clone(); let capture_block = Closure::from_value(replacement)?; diff --git a/crates/nu-command/src/filters/upsert.rs b/crates/nu-command/src/filters/upsert.rs index 6b99315cbb..a7761973f7 100644 --- a/crates/nu-command/src/filters/upsert.rs +++ b/crates/nu-command/src/filters/upsert.rs @@ -148,7 +148,7 @@ fn upsert( match input { PipelineData::Value(mut value, metadata) => { - if replacement.as_block().is_ok() { + if replacement.coerce_block().is_ok() { match (cell_path.members.first(), &mut value) { (Some(PathMember::String { .. }), Value::List { vals, .. }) => { let span = replacement.span(); @@ -214,7 +214,7 @@ fn upsert( if path.is_empty() { let span = replacement.span(); let value = stream.next().unwrap_or(Value::nothing(span)); - if replacement.as_block().is_ok() { + if replacement.coerce_block().is_ok() { let capture_block = Closure::from_value(replacement)?; let block = engine_state.get_block(capture_block.block_id); let mut stack = stack.captures_to_stack(capture_block.captures); @@ -239,7 +239,7 @@ fn upsert( pre_elems.push(replacement); } } else if let Some(mut value) = stream.next() { - if replacement.as_block().is_ok() { + if replacement.coerce_block().is_ok() { upsert_single_value_by_closure( &mut value, replacement, @@ -265,7 +265,7 @@ fn upsert( .into_iter() .chain(stream) .into_pipeline_data_with_metadata(metadata, ctrlc)) - } else if replacement.as_block().is_ok() { + } else if replacement.coerce_block().is_ok() { let engine_state = engine_state.clone(); let replacement_span = replacement.span(); let capture_block = Closure::from_value(replacement)?; diff --git a/crates/nu-command/src/formats/from/yaml.rs b/crates/nu-command/src/formats/from/yaml.rs index adc98ec888..abe38ef5cb 100644 --- a/crates/nu-command/src/formats/from/yaml.rs +++ b/crates/nu-command/src/formats/from/yaml.rs @@ -293,8 +293,8 @@ mod test { ); } else { assert_eq!( - actual.unwrap().into_string("", &config), - tc.expected.unwrap().into_string("", &config) + actual.unwrap().to_expanded_string("", &config), + tc.expected.unwrap().to_expanded_string("", &config) ); } } diff --git a/crates/nu-command/src/formats/to/delimited.rs b/crates/nu-command/src/formats/to/delimited.rs index 13e7dfd7b5..4bed0c4ec9 100644 --- a/crates/nu-command/src/formats/to/delimited.rs +++ b/crates/nu-command/src/formats/to/delimited.rs @@ -119,7 +119,7 @@ fn to_string_tagged_value( | Value::CustomValue { .. } | Value::Filesize { .. } | Value::CellPath { .. } - | Value::Float { .. } => Ok(v.clone().into_abbreviated_string(config)), + | Value::Float { .. } => Ok(v.clone().to_abbreviated_string(config)), Value::Date { val, .. } => Ok(val.to_string()), Value::Nothing { .. } => Ok(String::new()), // Propagate existing errors diff --git a/crates/nu-command/src/formats/to/md.rs b/crates/nu-command/src/formats/to/md.rs index e85b223c67..25b3237290 100644 --- a/crates/nu-command/src/formats/to/md.rs +++ b/crates/nu-command/src/formats/to/md.rs @@ -120,12 +120,12 @@ fn fragment(input: Value, pretty: bool, config: &Config) -> String { }; out.push_str(&markup); - out.push_str(&data.into_string("|", config)); + out.push_str(&data.to_expanded_string("|", config)); } _ => out = table(input.into_pipeline_data(), pretty, config), } } else { - out = input.into_string("|", config) + out = input.to_expanded_string("|", config) } out.push('\n'); @@ -168,7 +168,7 @@ fn table(input: PipelineData, pretty: bool, config: &Config) -> String { .get(&headers[i]) .cloned() .unwrap_or_else(|| Value::nothing(span)) - .into_string(", ", config); + .to_expanded_string(", ", config); let new_column_width = value_string.len(); escaped_row.push(value_string); @@ -180,7 +180,7 @@ fn table(input: PipelineData, pretty: bool, config: &Config) -> String { } p => { let value_string = - v_htmlescape::escape(&p.into_abbreviated_string(config)).to_string(); + v_htmlescape::escape(&p.to_abbreviated_string(config)).to_string(); escaped_row.push(value_string); } } @@ -215,7 +215,7 @@ pub fn group_by(values: PipelineData, head: Span, config: &Config) -> (PipelineD .or_insert_with(|| vec![val.clone()]); } else { lists - .entry(val.into_string(",", config)) + .entry(val.to_expanded_string(",", config)) .and_modify(|v: &mut Vec| v.push(val.clone())) .or_insert_with(|| vec![val.clone()]); } diff --git a/crates/nu-command/src/generators/seq_date.rs b/crates/nu-command/src/generators/seq_date.rs index de2c1e2b20..052c33bfec 100644 --- a/crates/nu-command/src/generators/seq_date.rs +++ b/crates/nu-command/src/generators/seq_date.rs @@ -205,7 +205,7 @@ pub fn run_seq_dates( } let in_format = match input_format { - Some(i) => match i.as_string() { + Some(i) => match i.coerce_into_string() { Ok(v) => v, Err(e) => { return Err(ShellError::GenericError { @@ -221,7 +221,7 @@ pub fn run_seq_dates( }; let out_format = match output_format { - Some(i) => match i.as_string() { + Some(o) => match o.coerce_into_string() { Ok(v) => v, Err(e) => { return Err(ShellError::GenericError { diff --git a/crates/nu-command/src/misc/tutor.rs b/crates/nu-command/src/misc/tutor.rs index ba84517718..f633a6751c 100644 --- a/crates/nu-command/src/misc/tutor.rs +++ b/crates/nu-command/src/misc/tutor.rs @@ -423,7 +423,7 @@ fn display(help: &str, engine_state: &EngineState, stack: &mut Stack, span: Span Value::string(item, Span::unknown()).into_pipeline_data(), ) { let result = output.into_value(Span::unknown()); - match result.as_string() { + match result.coerce_into_string() { Ok(s) => { build.push_str(&s); } diff --git a/crates/nu-command/src/network/http/client.rs b/crates/nu-command/src/network/http/client.rs index e251f08ed2..1b89bc93d2 100644 --- a/crates/nu-command/src/network/http/client.rs +++ b/crates/nu-command/src/network/http/client.rs @@ -73,7 +73,7 @@ pub fn http_parse_url( span: Span, raw_url: Value, ) -> Result<(String, Url), ShellError> { - let requested_url = raw_url.as_string()?; + let requested_url = raw_url.coerce_into_string()?; let url = match url::Url::parse(&requested_url) { Ok(u) => u, Err(_e) => { @@ -222,8 +222,7 @@ pub fn send_request( let mut data: Vec<(String, String)> = Vec::with_capacity(val.len()); for (col, val) in val { - let val_string = val.as_string()?; - data.push((col, val_string)) + data.push((col, val.coerce_into_string()?)) } let request_fn = move || { @@ -245,7 +244,7 @@ pub fn send_request( let data = vals .chunks(2) - .map(|it| Ok((it[0].as_string()?, it[1].as_string()?))) + .map(|it| Ok((it[0].coerce_string()?, it[1].coerce_string()?))) .collect::, ShellErrorOrRequestError>>()?; let request_fn = move || { @@ -364,7 +363,7 @@ pub fn request_add_custom_headers( // primitive values ([key1 val1 key2 val2]) for row in table.chunks(2) { if row.len() == 2 { - custom_headers.insert(row[0].as_string()?, row[1].clone()); + custom_headers.insert(row[0].coerce_string()?, row[1].clone()); } } } @@ -380,9 +379,9 @@ pub fn request_add_custom_headers( } }; - for (k, v) in &custom_headers { - if let Ok(s) = v.as_string() { - request = request.set(k, &s); + for (k, v) in custom_headers { + if let Ok(s) = v.coerce_into_string() { + request = request.set(&k, &s); } } } @@ -684,17 +683,11 @@ pub fn request_handle_response_headers( } fn retrieve_http_proxy_from_env(engine_state: &EngineState, stack: &mut Stack) -> Option { - let proxy_value: Option = stack + stack .get_env_var(engine_state, "http_proxy") .or(stack.get_env_var(engine_state, "HTTP_PROXY")) .or(stack.get_env_var(engine_state, "https_proxy")) .or(stack.get_env_var(engine_state, "HTTPS_PROXY")) - .or(stack.get_env_var(engine_state, "ALL_PROXY")); - match proxy_value { - Some(value) => match value.as_string() { - Ok(proxy) => Some(proxy), - _ => None, - }, - _ => None, - } + .or(stack.get_env_var(engine_state, "ALL_PROXY")) + .and_then(|proxy| proxy.coerce_into_string().ok()) } diff --git a/crates/nu-command/src/network/url/build_query.rs b/crates/nu-command/src/network/url/build_query.rs index 075b39f733..c2c561f88b 100644 --- a/crates/nu-command/src/network/url/build_query.rs +++ b/crates/nu-command/src/network/url/build_query.rs @@ -70,7 +70,7 @@ fn to_url(input: PipelineData, head: Span) -> Result { Value::Record { ref val, .. } => { let mut row_vec = vec![]; for (k, v) in val { - match v.as_string() { + match v.coerce_string() { Ok(s) => { row_vec.push((k.clone(), s.to_string())); } diff --git a/crates/nu-command/src/network/url/join.rs b/crates/nu-command/src/network/url/join.rs index 2a93d33578..52668d1a09 100644 --- a/crates/nu-command/src/network/url/join.rs +++ b/crates/nu-command/src/network/url/join.rs @@ -181,10 +181,10 @@ impl UrlComponents { if key == "params" { return match value { - Value::Record { ref val, .. } => { + Value::Record { val, .. } => { let mut qs = val - .iter() - .map(|(k, v)| match v.as_string() { + .into_iter() + .map(|(k, v)| match v.coerce_into_string() { Ok(val) => Ok(format!("{k}={val}")), Err(err) => Err(err), }) @@ -202,7 +202,7 @@ impl UrlComponents { // if query is present it means that also query_span is set. return Err(ShellError::IncompatibleParameters { left_message: format!("Mismatch, qs from params is: {qs}"), - left_span: value.span(), + left_span: value_span, right_message: format!("instead query is: {q}"), right_span: self.query_span.unwrap_or(Span::unknown()), }); @@ -224,7 +224,7 @@ impl UrlComponents { } // apart from port and params all other keys are strings. - let s = value.as_string()?; // If value fails String conversion, just output this ShellError + let s = value.coerce_into_string()?; // If value fails String conversion, just output this ShellError if !Self::check_empty_string_ok(&key, &s, value_span)? { return Ok(self); } @@ -259,7 +259,7 @@ impl UrlComponents { // if query is present it means that also params_span is set. return Err(ShellError::IncompatibleParameters { left_message: format!("Mismatch, query param is: {s}"), - left_span: value.span(), + left_span: value_span, right_message: format!("instead qs from params is: {q}"), right_span: self.params_span.unwrap_or(Span::unknown()), }); @@ -268,7 +268,7 @@ impl UrlComponents { Ok(Self { query: Some(format!("?{s}")), - query_span: Some(value.span()), + query_span: Some(value_span), ..self }) } diff --git a/crates/nu-command/src/network/url/parse.rs b/crates/nu-command/src/network/url/parse.rs index 330ff786ba..1d54a08957 100644 --- a/crates/nu-command/src/network/url/parse.rs +++ b/crates/nu-command/src/network/url/parse.rs @@ -75,7 +75,7 @@ impl Command for SubCommand { } fn get_url_string(value: &Value, engine_state: &EngineState) -> String { - value.into_string("", engine_state.get_config()) + value.to_expanded_string("", engine_state.get_config()) } fn parse(value: Value, head: Span, engine_state: &EngineState) -> Result { diff --git a/crates/nu-command/src/path/join.rs b/crates/nu-command/src/path/join.rs index 1dfc75a5e8..469469c81e 100644 --- a/crates/nu-command/src/path/join.rs +++ b/crates/nu-command/src/path/join.rs @@ -213,7 +213,7 @@ fn join_single(path: &Path, head: Span, args: &Arguments) -> Value { } fn join_list(parts: &[Value], head: Span, span: Span, args: &Arguments) -> Value { - let path: Result = parts.iter().map(Value::as_string).collect(); + let path: Result = parts.iter().map(Value::coerce_string).collect(); match path { Ok(ref path) => join_single(path, head, args), @@ -262,14 +262,14 @@ fn merge_record(record: &Record, head: Span, span: Span) -> Result Result Result Result Result nu_style.fg = Some(v.as_string()?), - "bg" => nu_style.bg = Some(v.as_string()?), - "attr" => nu_style.attr = Some(v.as_string()?), + "fg" => nu_style.fg = Some(v.coerce_into_string()?), + "bg" => nu_style.bg = Some(v.coerce_into_string()?), + "attr" => nu_style.attr = Some(v.coerce_into_string()?), _ => { return Err(ShellError::IncompatibleParametersSingle { msg: format!("unknown ANSI format key: expected one of ['fg', 'bg', 'attr'], found '{k}'"), - span: code.span(), + span, }) } } diff --git a/crates/nu-command/src/platform/ansi/strip.rs b/crates/nu-command/src/platform/ansi/strip.rs index 8f542853ec..71d48fc5a6 100644 --- a/crates/nu-command/src/platform/ansi/strip.rs +++ b/crates/nu-command/src/platform/ansi/strip.rs @@ -81,7 +81,7 @@ fn action(input: &Value, args: &Arguments, _span: Span) -> Value { other => { // Fake stripping ansi for other types and just show the abbreviated string // instead of showing an error message - Value::string(other.into_abbreviated_string(&args.config), span) + Value::string(other.to_abbreviated_string(&args.config), span) } } } diff --git a/crates/nu-command/src/platform/input/list.rs b/crates/nu-command/src/platform/input/list.rs index 990d376fb6..598a3914b0 100644 --- a/crates/nu-command/src/platform/input/list.rs +++ b/crates/nu-command/src/platform/input/list.rs @@ -95,9 +95,9 @@ impl Command for InputList { let display_value = if let Some(ref cellpath) = display_path { val.clone() .follow_cell_path(&cellpath.members, false)? - .into_string(", ", engine_state.get_config()) + .to_expanded_string(", ", engine_state.get_config()) } else { - val.into_string(", ", engine_state.get_config()) + val.to_expanded_string(", ", engine_state.get_config()) }; Ok(Options { name: display_value, diff --git a/crates/nu-command/src/random/float.rs b/crates/nu-command/src/random/float.rs index e86fa4866a..8e3bef2002 100644 --- a/crates/nu-command/src/random/float.rs +++ b/crates/nu-command/src/random/float.rs @@ -81,9 +81,9 @@ fn float( range_span = spanned_range.span; if r.is_end_inclusive() { - (r.from.as_float()?, r.to.as_float()?) - } else if r.to.as_float()? >= 1.0 { - (r.from.as_float()?, r.to.as_float()? - 1.0) + (r.from.coerce_float()?, r.to.coerce_float()?) + } else if r.to.coerce_float()? >= 1.0 { + (r.from.coerce_float()?, r.to.coerce_float()? - 1.0) } else { (0.0, 0.0) } diff --git a/crates/nu-command/src/sort_utils.rs b/crates/nu-command/src/sort_utils.rs index 778df33138..1c50e21b67 100644 --- a/crates/nu-command/src/sort_utils.rs +++ b/crates/nu-command/src/sort_utils.rs @@ -137,7 +137,10 @@ pub fn sort( }; if natural { - match (folded_left.as_string(), folded_right.as_string()) { + match ( + folded_left.coerce_into_string(), + folded_right.coerce_into_string(), + ) { (Ok(left), Ok(right)) => compare_str(left, right), _ => Ordering::Equal, } @@ -147,7 +150,7 @@ pub fn sort( .unwrap_or(Ordering::Equal) } } else if natural { - match (a.as_string(), b.as_string()) { + match (a.coerce_string(), b.coerce_string()) { (Ok(left), Ok(right)) => compare_str(left, right), _ => Ordering::Equal, } @@ -196,7 +199,10 @@ pub fn compare( _ => right_res, }; if natural { - match (folded_left.as_string(), folded_right.as_string()) { + match ( + folded_left.coerce_into_string(), + folded_right.coerce_into_string(), + ) { (Ok(left), Ok(right)) => compare_str(left, right), _ => Ordering::Equal, } @@ -206,7 +212,10 @@ pub fn compare( .unwrap_or(Ordering::Equal) } } else if natural { - match (left_res.as_string(), right_res.as_string()) { + match ( + left_res.coerce_into_string(), + right_res.coerce_into_string(), + ) { (Ok(left), Ok(right)) => compare_str(left, right), _ => Ordering::Equal, } diff --git a/crates/nu-command/src/stor/create.rs b/crates/nu-command/src/stor/create.rs index 2f2099477c..71a6c6bb21 100644 --- a/crates/nu-command/src/stor/create.rs +++ b/crates/nu-command/src/stor/create.rs @@ -89,7 +89,7 @@ fn process( new_table_name ); for (column_name, column_datatype) in record { - match column_datatype.as_string()?.as_str() { + match column_datatype.coerce_string()?.as_str() { "int" => { create_stmt.push_str(&format!("{} INTEGER, ", column_name)); } diff --git a/crates/nu-command/src/strings/detect_columns.rs b/crates/nu-command/src/strings/detect_columns.rs index f2cecdfedd..437c90014c 100644 --- a/crates/nu-command/src/strings/detect_columns.rs +++ b/crates/nu-command/src/strings/detect_columns.rs @@ -227,7 +227,7 @@ fn detect_columns( .iter() .take(end_index) .skip(start_index) - .map(|v| v.as_string().unwrap_or_default()) + .map(|v| v.coerce_string().unwrap_or_default()) .join(" "); let binding = Value::string(combined, Span::unknown()); let last_seg = vals.split_off(end_index); diff --git a/crates/nu-command/src/strings/encode_decode/encoding.rs b/crates/nu-command/src/strings/encode_decode/encoding.rs index 2a1e4bedc1..a063820d4c 100644 --- a/crates/nu-command/src/strings/encode_decode/encoding.rs +++ b/crates/nu-command/src/strings/encode_decode/encoding.rs @@ -115,10 +115,10 @@ mod test { }; let encoded = encode(test_span, encoding.clone(), expected, test_span, true).unwrap(); - let encoded = encoded.as_binary().unwrap(); + let encoded = encoded.coerce_into_binary().unwrap(); - let decoded = decode(test_span, encoding, encoded).unwrap(); - let decoded = decoded.as_string().unwrap(); + let decoded = decode(test_span, encoding, &encoded).unwrap(); + let decoded = decoded.coerce_into_string().unwrap(); assert_eq!(decoded, expected); } diff --git a/crates/nu-command/src/strings/format/date.rs b/crates/nu-command/src/strings/format/date.rs index 7fa09ddd5a..1555ee3c99 100644 --- a/crates/nu-command/src/strings/format/date.rs +++ b/crates/nu-command/src/strings/format/date.rs @@ -159,7 +159,7 @@ fn format_helper(value: Value, formatter: &str, formatter_span: Span, head_span: } _ => Value::error( ShellError::DatetimeParseError { - msg: value.debug_value(), + msg: value.to_debug_string(), span: head_span, }, head_span, @@ -180,7 +180,7 @@ fn format_helper_rfc2822(value: Value, span: Span) -> Value { } _ => Value::error( ShellError::DatetimeParseError { - msg: value.debug_value(), + msg: value.to_debug_string(), span, }, span, diff --git a/crates/nu-command/src/strings/format/duration.rs b/crates/nu-command/src/strings/format/duration.rs index 695294748e..572cc4dcfe 100644 --- a/crates/nu-command/src/strings/format/duration.rs +++ b/crates/nu-command/src/strings/format/duration.rs @@ -67,7 +67,7 @@ impl Command for FormatDuration { ) -> Result { let format_value = call .req::(engine_state, stack, 0)? - .as_string()? + .coerce_into_string()? .to_ascii_lowercase(); let cell_paths: Vec = call.rest(engine_state, stack, 1)?; let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths); diff --git a/crates/nu-command/src/strings/format/filesize.rs b/crates/nu-command/src/strings/format/filesize.rs index f839af1608..c5bf99516b 100644 --- a/crates/nu-command/src/strings/format/filesize.rs +++ b/crates/nu-command/src/strings/format/filesize.rs @@ -64,7 +64,7 @@ impl Command for FormatFilesize { ) -> Result { let format_value = call .req::(engine_state, stack, 0)? - .as_string()? + .coerce_into_string()? .to_ascii_lowercase(); let cell_paths: Vec = call.rest(engine_state, stack, 1)?; let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths); diff --git a/crates/nu-command/src/strings/parse.rs b/crates/nu-command/src/strings/parse.rs index 186db1886a..638cd5a93b 100644 --- a/crates/nu-command/src/strings/parse.rs +++ b/crates/nu-command/src/strings/parse.rs @@ -150,7 +150,8 @@ fn operate( let mut parsed: Vec = Vec::new(); for v in input { - match v.as_string() { + let v_span = v.span(); + match v.coerce_into_string() { Ok(s) => { let results = regex_pattern.captures_iter(&s); @@ -168,7 +169,6 @@ fn operate( } }; - let v_span = v.span(); let record = columns .iter() .zip(captures.iter().skip(1)) @@ -185,7 +185,7 @@ fn operate( return Err(ShellError::PipelineMismatch { exp_input_type: "string".into(), dst_span: head, - src_span: v.span(), + src_span: v_span, }) } } @@ -322,21 +322,22 @@ impl Iterator for ParseStreamer { } let v = self.stream.next()?; + let span = v.span(); - let Ok(s) = v.as_string() else { + let Ok(s) = v.coerce_into_string() else { return Some(Value::error( ShellError::PipelineMismatch { exp_input_type: "string".into(), dst_span: self.span, - src_span: v.span(), + src_span: span, }, - v.span(), + span, )); }; let parsed = stream_helper( self.regex.clone(), - v.span(), + span, s, self.columns.clone(), &mut self.excess, diff --git a/crates/nu-command/src/strings/split/chars.rs b/crates/nu-command/src/strings/split/chars.rs index 76096cca14..fdbf0a2bc4 100644 --- a/crates/nu-command/src/strings/split/chars.rs +++ b/crates/nu-command/src/strings/split/chars.rs @@ -124,7 +124,7 @@ fn split_chars_helper(v: &Value, name: Span, graphemes: bool) -> Value { Value::Error { error, .. } => Value::error(*error.clone(), span), v => { let v_span = v.span(); - if let Ok(s) = v.as_string() { + if let Ok(s) = v.coerce_string() { Value::list( if graphemes { s.graphemes(true) diff --git a/crates/nu-command/src/strings/split/column.rs b/crates/nu-command/src/strings/split/column.rs index ec6ca887d2..b1a8d561d0 100644 --- a/crates/nu-command/src/strings/split/column.rs +++ b/crates/nu-command/src/strings/split/column.rs @@ -148,7 +148,7 @@ fn split_column_helper( collapse_empty: bool, head: Span, ) -> Vec { - if let Ok(s) = v.as_string() { + if let Ok(s) = v.coerce_string() { let split_result: Vec<_> = separator .split(&s) .filter(|x| !(collapse_empty && x.is_empty())) diff --git a/crates/nu-command/src/strings/split/list.rs b/crates/nu-command/src/strings/split/list.rs index 1065ca9ed6..bdb1aff79e 100644 --- a/crates/nu-command/src/strings/split/list.rs +++ b/crates/nu-command/src/strings/split/list.rs @@ -27,8 +27,8 @@ impl Command for SubCommand { "The value that denotes what separates the list.", ) .switch( - "regex", - "separator is a regular expression, matching values that can be coerced into a string", + "regex", + "separator is a regular expression, matching values that can be coerced into a string", Some('r')) .category(Category::Filters) } @@ -160,7 +160,7 @@ enum Matcher { impl Matcher { pub fn new(regex: bool, lhs: Value) -> Result { if regex { - Ok(Matcher::Regex(Regex::new(&lhs.as_string()?).map_err( + Ok(Matcher::Regex(Regex::new(&lhs.coerce_string()?).map_err( |e| ShellError::GenericError { error: "Error with regular expression".into(), msg: e.to_string(), @@ -180,7 +180,7 @@ impl Matcher { pub fn compare(&self, rhs: &Value) -> Result { Ok(match self { Matcher::Regex(regex) => { - if let Ok(rhs_str) = rhs.as_string() { + if let Ok(rhs_str) = rhs.coerce_string() { regex.is_match(&rhs_str) } else { false diff --git a/crates/nu-command/src/strings/split/row.rs b/crates/nu-command/src/strings/split/row.rs index 298e283cf4..0f23c4ae70 100644 --- a/crates/nu-command/src/strings/split/row.rs +++ b/crates/nu-command/src/strings/split/row.rs @@ -152,7 +152,7 @@ fn split_row_helper(v: &Value, regex: &Regex, max_split: Option, name: Sp v => { let v_span = v.span(); - if let Ok(s) = v.as_string() { + if let Ok(s) = v.coerce_string() { match max_split { Some(max_split) => regex .splitn(&s, max_split) diff --git a/crates/nu-command/src/strings/split/words.rs b/crates/nu-command/src/strings/split/words.rs index f3f200116c..0ed6cb804c 100644 --- a/crates/nu-command/src/strings/split/words.rs +++ b/crates/nu-command/src/strings/split/words.rs @@ -158,7 +158,7 @@ fn split_words_helper(v: &Value, word_length: Option, span: Span, graphem Value::Error { error, .. } => Value::error(*error.clone(), v_span), v => { let v_span = v.span(); - if let Ok(s) = v.as_string() { + if let Ok(s) = v.coerce_string() { // let splits = s.unicode_words(); // let words = trim_to_words(s); // let words: Vec<&str> = s.split_whitespace().collect(); diff --git a/crates/nu-command/src/strings/str_/expand.rs b/crates/nu-command/src/strings/str_/expand.rs index b35039d742..84cb907919 100644 --- a/crates/nu-command/src/strings/str_/expand.rs +++ b/crates/nu-command/src/strings/str_/expand.rs @@ -199,10 +199,10 @@ impl Command for SubCommand { input.map( move |v| { let value_span = v.span(); - match v.as_string() { + match v.coerce_into_string() { Ok(s) => { let contents = if is_path { s.replace('\\', "\\\\") } else { s }; - str_expand(&contents, span, v.span()) + str_expand(&contents, span, value_span) } Err(_) => Value::error( ShellError::PipelineMismatch { diff --git a/crates/nu-command/src/strings/str_/join.rs b/crates/nu-command/src/strings/str_/join.rs index 0fef059493..1533be5bcc 100644 --- a/crates/nu-command/src/strings/str_/join.rs +++ b/crates/nu-command/src/strings/str_/join.rs @@ -49,19 +49,19 @@ impl Command for StrJoin { let config = engine_state.get_config(); // let output = input.collect_string(&separator.unwrap_or_default(), &config)?; - // Hmm, not sure what we actually want. If you don't use debug_string, Date comes out as human readable - // which feels funny + // Hmm, not sure what we actually want. + // `to_formatted_string` formats dates as human readable which feels funny. let mut strings: Vec = vec![]; for value in input { - match value { + let str = match value { Value::Error { error, .. } => { return Err(*error); } - value => { - strings.push(value.debug_string("\n", config)); - } - } + Value::Date { val, .. } => format!("{val:?}"), + value => value.to_expanded_string("\n", config), + }; + strings.push(str); } let output = if let Some(separator) = separator { diff --git a/crates/nu-command/src/strings/str_/stats.rs b/crates/nu-command/src/strings/str_/stats.rs index d40374c3f4..fbd7f9ea79 100644 --- a/crates/nu-command/src/strings/str_/stats.rs +++ b/crates/nu-command/src/strings/str_/stats.rs @@ -100,7 +100,7 @@ fn stats( return Value::error(*error, span); } // Now, check if it's a string. - match v.as_string() { + match v.coerce_into_string() { Ok(s) => counter(&s, span), Err(_) => Value::error( ShellError::PipelineMismatch { diff --git a/crates/nu-command/src/system/registry_query.rs b/crates/nu-command/src/system/registry_query.rs index 63534e9c2b..050457602f 100644 --- a/crates/nu-command/src/system/registry_query.rs +++ b/crates/nu-command/src/system/registry_query.rs @@ -296,13 +296,13 @@ fn no_expand_does_not_expand() { // normally we do expand let nu_val_expanded = reg_value_to_nu_string(reg_val(), Span::unknown(), false); - assert!(nu_val_expanded.as_string().is_ok()); - assert_ne!(nu_val_expanded.as_string().unwrap(), unexpanded); + assert!(nu_val_expanded.coerce_string().is_ok()); + assert_ne!(nu_val_expanded.coerce_string().unwrap(), unexpanded); // unless we skip expansion let nu_val_skip_expand = reg_value_to_nu_string(reg_val(), Span::unknown(), true); - assert!(nu_val_skip_expand.as_string().is_ok()); - assert_eq!(nu_val_skip_expand.as_string().unwrap(), unexpanded); + assert!(nu_val_skip_expand.coerce_string().is_ok()); + assert_eq!(nu_val_skip_expand.coerce_string().unwrap(), unexpanded); } fn reg_value_to_nu_list_string(reg_value: winreg::RegValue, call_span: Span) -> nu_protocol::Value { diff --git a/crates/nu-command/src/system/run_external.rs b/crates/nu-command/src/system/run_external.rs index edd00f4879..ed3708e0ce 100644 --- a/crates/nu-command/src/system/run_external.rs +++ b/crates/nu-command/src/system/run_external.rs @@ -123,7 +123,7 @@ pub fn create_external_command( let span = value.span(); value - .as_string() + .coerce_string() .map(|item| Spanned { item, span }) .map_err(|_| ShellError::ExternalCommand { label: format!("Cannot convert {} to a string", value.get_type()), diff --git a/crates/nu-command/src/viewers/griddle.rs b/crates/nu-command/src/viewers/griddle.rs index 7d9b72fd37..217cfabfed 100644 --- a/crates/nu-command/src/viewers/griddle.rs +++ b/crates/nu-command/src/viewers/griddle.rs @@ -114,7 +114,7 @@ prints out the list properly."# let mut items = vec![]; for (i, (c, v)) in val.into_iter().enumerate() { - items.push((i, c, v.into_string(", ", config))) + items.push((i, c, v.to_expanded_string(", ", config))) } Ok(create_grid_output( @@ -265,10 +265,14 @@ fn convert_to_list( let mut data = vec![]; for (row_num, item) in iter.enumerate() { + if let Value::Error { error, .. } = item { + return Err(*error); + } + let mut row = vec![row_num.to_string()]; if headers.is_empty() { - row.push(item.nonerror_into_string(", ", config)?) + row.push(item.to_expanded_string(", ", config)) } else { for header in headers.iter().skip(1) { let result = match &item { @@ -277,7 +281,12 @@ fn convert_to_list( }; match result { - Some(value) => row.push(value.nonerror_into_string(", ", config)?), + Some(value) => { + if let Value::Error { error, .. } = item { + return Err(*error); + } + row.push(value.to_expanded_string(", ", config)); + } None => row.push(String::new()), } } diff --git a/crates/nu-command/tests/commands/database/into_sqlite.rs b/crates/nu-command/tests/commands/database/into_sqlite.rs index 736a84c1e7..585fc44515 100644 --- a/crates/nu-command/tests/commands/database/into_sqlite.rs +++ b/crates/nu-command/tests/commands/database/into_sqlite.rs @@ -180,7 +180,9 @@ fn into_sqlite_big_insert() { span: Span::unknown(), optional: false, }], - Box::new(|dateval| Value::string(dateval.as_string().unwrap(), dateval.span())), + Box::new(|dateval| { + Value::string(dateval.coerce_string().unwrap(), dateval.span()) + }), ) .unwrap(); diff --git a/crates/nu-engine/src/documentation.rs b/crates/nu-engine/src/documentation.rs index 6de0554b28..b626547d40 100644 --- a/crates/nu-engine/src/documentation.rs +++ b/crates/nu-engine/src/documentation.rs @@ -51,7 +51,7 @@ fn nu_highlight_string(code_string: &str, engine_state: &EngineState, stack: &mu Value::string(code_string, Span::unknown()).into_pipeline_data(), ) { let result = output.into_value(Span::unknown()); - if let Ok(s) = result.as_string() { + if let Ok(s) = result.coerce_into_string() { return s; // successfully highlighted string } } @@ -139,7 +139,7 @@ fn get_documentation( if !sig.named.is_empty() { long_desc.push_str(&get_flags_section(Some(engine_state), sig, |v| { nu_highlight_string( - &v.into_string_parsable(", ", &engine_state.config), + &v.to_parsable_string(", ", &engine_state.config), engine_state, stack, ) @@ -187,7 +187,7 @@ fn get_documentation( format!( " (optional, default: {})", nu_highlight_string( - &value.into_string_parsable(", ", &engine_state.config), + &value.to_parsable_string(", ", &engine_state.config), engine_state, stack ) @@ -280,7 +280,7 @@ fn get_documentation( ) { Ok(output) => { let result = output.into_value(Span::unknown()); - match result.as_string() { + match result.coerce_into_string() { Ok(s) => { let _ = write!(long_desc, "\n > {s}\n"); } @@ -316,7 +316,7 @@ fn get_documentation( let _ = writeln!( long_desc, " {}", - item.into_string("", engine_state.get_config()) + item.to_expanded_string("", engine_state.get_config()) .replace('\n', "\n ") .trim() ); @@ -390,7 +390,7 @@ fn get_argument_for_color_value( }, Expression { expr: Expr::String( - v.clone().into_string("", engine_state.get_config()), + v.clone().to_expanded_string("", engine_state.get_config()), ), span, ty: Type::String, diff --git a/crates/nu-engine/src/env.rs b/crates/nu-engine/src/env.rs index ea8103b024..7df0dfbd7b 100644 --- a/crates/nu-engine/src/env.rs +++ b/crates/nu-engine/src/env.rs @@ -98,10 +98,10 @@ pub fn env_to_string( stack: &Stack, ) -> Result { match get_converted_value(engine_state, stack, env_name, value, "to_string") { - ConversionResult::Ok(v) => Ok(v.as_string()?), + ConversionResult::Ok(v) => Ok(v.coerce_into_string()?), ConversionResult::ConversionError(e) => Err(e), ConversionResult::GeneralError(e) => Err(e), - ConversionResult::CellPathError => match value.as_string() { + ConversionResult::CellPathError => match value.coerce_string() { Ok(s) => Ok(s), Err(_) => { if env_name == ENV_PATH_NAME { @@ -110,7 +110,7 @@ pub fn env_to_string( Value::List { vals, .. } => { let paths = vals .iter() - .map(|v| v.as_string()) + .map(|v| v.coerce_string()) .collect::, _>>()?; match std::env::join_paths(paths) { @@ -333,7 +333,7 @@ pub fn find_in_dirs_env( .ok()? .iter() .map(|lib_dir| -> Option { - let dir = lib_dir.as_path().ok()?; + let dir = lib_dir.to_path().ok()?; let dir_abs = canonicalize_with(dir, &cwd).ok()?; canonicalize_with(filename, dir_abs).ok() }) diff --git a/crates/nu-explore/src/commands/expand.rs b/crates/nu-explore/src/commands/expand.rs index faab60e41c..122ce3c19e 100644 --- a/crates/nu-explore/src/commands/expand.rs +++ b/crates/nu-explore/src/commands/expand.rs @@ -85,7 +85,7 @@ fn convert_value_to_string(value: Value, engine_state: &EngineState, stack: &mut let has_single_value = vals.len() == 1 && vals[0].len() == 1; if !has_no_head && has_single_value { let config = engine_state.get_config(); - vals[0][0].into_abbreviated_string(config) + vals[0][0].to_abbreviated_string(config) } else { let ctrlc = engine_state.ctrlc.clone(); let config = engine_state.get_config(); diff --git a/crates/nu-explore/src/commands/nu.rs b/crates/nu-explore/src/commands/nu.rs index b36c009d25..635a9ad2a3 100644 --- a/crates/nu-explore/src/commands/nu.rs +++ b/crates/nu-explore/src/commands/nu.rs @@ -86,7 +86,7 @@ impl ViewCommand for NuCmd { let (columns, values) = collect_pipeline(pipeline); if let Some(value) = has_simple_value(&values) { - let text = value.into_abbreviated_string(&engine_state.config); + let text = value.to_abbreviated_string(&engine_state.config); return Ok(NuView::Preview(Preview::new(&text))); } diff --git a/crates/nu-explore/src/lib.rs b/crates/nu-explore/src/lib.rs index 79c715278b..3a7e5f652a 100644 --- a/crates/nu-explore/src/lib.rs +++ b/crates/nu-explore/src/lib.rs @@ -50,7 +50,7 @@ fn run_pager( p.show_message("For help type :help"); if let Some(value) = has_simple_value(&data) { - let text = value.into_abbreviated_string(config.nu_config); + let text = value.to_abbreviated_string(config.nu_config); let view = Some(Page::new(Preview::new(&text), true)); return p.run(engine_state, stack, ctrlc, view, commands); } diff --git a/crates/nu-explore/src/pager/mod.rs b/crates/nu-explore/src/pager/mod.rs index 91ba6ee034..129c42305f 100644 --- a/crates/nu-explore/src/pager/mod.rs +++ b/crates/nu-explore/src/pager/mod.rs @@ -1008,7 +1008,7 @@ fn cmd_input_key_event(buf: &mut CommandBuf, key: &KeyEvent) -> bool { } fn value_as_style(style: &mut nu_ansi_term::Style, value: &Value) -> bool { - match value.as_string() { + match value.coerce_string() { Ok(s) => { *style = lookup_ansi_color_style(&s); true diff --git a/crates/nu-explore/src/views/record/mod.rs b/crates/nu-explore/src/views/record/mod.rs index 514735f761..163a6a5504 100644 --- a/crates/nu-explore/src/views/record/mod.rs +++ b/crates/nu-explore/src/views/record/mod.rs @@ -331,7 +331,7 @@ impl View for RecordView<'_> { if let Some(hm) = cfg.config.get("table").and_then(create_map) { self.theme = theme_from_config(&hm); - if let Some(orientation) = hm.get("orientation").and_then(|v| v.as_string().ok()) { + if let Some(orientation) = hm.get("orientation").and_then(|v| v.coerce_string().ok()) { let orientation = match orientation.as_str() { "left" => Some(Orientation::Left), "top" => Some(Orientation::Top), @@ -648,7 +648,7 @@ fn convert_records_to_string( .map(|row| { row.iter() .map(|value| { - let text = value.clone().into_abbreviated_string(cfg); + let text = value.clone().to_abbreviated_string(cfg); let float_precision = cfg.float_precision as usize; make_styled_string(style_computer, text, Some(value), float_precision) @@ -857,7 +857,7 @@ fn config_get_bool(config: &ConfigMap, key: &str, default: bool) -> bool { fn config_get_usize(config: &ConfigMap, key: &str, default: usize) -> usize { config .get(key) - .and_then(|v| v.as_string().ok()) + .and_then(|v| v.coerce_string().ok()) .and_then(|s| s.parse::().ok()) .unwrap_or(default) } diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index f4072682c2..e8b0f2bf17 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -2646,7 +2646,7 @@ pub fn parse_overlay_new(working_set: &mut StateWorkingSet, call: Box) -> let (overlay_name, _) = if let Some(expr) = call.positional_nth(0) { match eval_constant(working_set, expr) { - Ok(val) => match val.as_string() { + Ok(val) => match val.coerce_into_string() { Ok(s) => (s, expr.span), Err(err) => { working_set.error(err.wrap(working_set, call_span)); @@ -2695,7 +2695,7 @@ pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box) -> let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) { match eval_constant(working_set, expr) { - Ok(val) => match val.as_string() { + Ok(val) => match val.coerce_into_string() { Ok(s) => (s, expr.span), Err(err) => { working_set.error(err.wrap(working_set, call_span)); @@ -2718,7 +2718,7 @@ pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box) -> let new_name = if let Some(kw_expression) = call.positional_nth(1) { if let Some(new_name_expression) = kw_expression.as_keyword() { match eval_constant(working_set, new_name_expression) { - Ok(val) => match val.as_string() { + Ok(val) => match val.coerce_into_string() { Ok(s) => Some(Spanned { item: s, span: new_name_expression.span, @@ -2916,7 +2916,7 @@ pub fn parse_overlay_hide(working_set: &mut StateWorkingSet, call: Box) -> let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) { match eval_constant(working_set, expr) { - Ok(val) => match val.as_string() { + Ok(val) => match val.coerce_into_string() { Ok(s) => (s, expr.span), Err(err) => { working_set.error(err.wrap(working_set, call_span)); @@ -3383,7 +3383,7 @@ pub fn parse_source(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeli } }; - let filename = match val.as_string() { + let filename = match val.coerce_into_string() { Ok(s) => s, Err(err) => { working_set.error(err.wrap(working_set, span(&spans[1..]))); @@ -3590,7 +3590,7 @@ pub fn parse_register(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipe let val = eval_constant(working_set, expr).map_err(|err| err.wrap(working_set, call.head))?; let filename = val - .as_string() + .coerce_into_string() .map_err(|err| err.wrap(working_set, call.head))?; let Some(path) = find_in_dirs(&filename, working_set, &cwd, PLUGIN_DIRS_VAR) else { @@ -3800,7 +3800,7 @@ pub fn find_in_dirs( .ok()? .iter() .map(|lib_dir| -> Option { - let dir = lib_dir.as_path().ok()?; + let dir = lib_dir.to_path().ok()?; let dir_abs = canonicalize_with(dir, actual_cwd).ok()?; canonicalize_with(filename, dir_abs).ok() }) @@ -3833,7 +3833,7 @@ pub fn find_in_dirs( if let Some(lib_dirs) = working_set.get_env_var(dirs_env) { if let Ok(dirs) = lib_dirs.as_list() { for lib_dir in dirs { - if let Ok(dir) = lib_dir.as_path() { + if let Ok(dir) = lib_dir.to_path() { // make sure the dir is absolute path if let Ok(dir_abs) = canonicalize_with(dir, actual_cwd) { if let Ok(path) = canonicalize_with(filename, dir_abs) { diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 327b1830f5..6fff91d26e 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -2795,7 +2795,7 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) - let head_expr = parse_value(working_set, *head_span, &SyntaxShape::Any); let (maybe_module_id, head_name) = match eval_constant(working_set, &head_expr) { - Ok(val) => match val.as_string() { + Ok(val) => match val.coerce_into_string() { Ok(s) => (working_set.find_module(s.as_bytes()), s.into_bytes()), Err(err) => { working_set.error(err.wrap(working_set, span(spans))); diff --git a/crates/nu-protocol/src/config/helper.rs b/crates/nu-protocol/src/config/helper.rs index b4119a5e3c..212ca7bced 100644 --- a/crates/nu-protocol/src/config/helper.rs +++ b/crates/nu-protocol/src/config/helper.rs @@ -15,7 +15,7 @@ pub(super) fn process_string_enum( E: Display, { let span = value.span(); - if let Ok(v) = value.as_string() { + if let Ok(v) = value.coerce_string() { match v.parse() { Ok(format) => { *config_point = format; diff --git a/crates/nu-protocol/src/config/mod.rs b/crates/nu-protocol/src/config/mod.rs index 49855b430f..e6a0c184a2 100644 --- a/crates/nu-protocol/src/config/mod.rs +++ b/crates/nu-protocol/src/config/mod.rs @@ -320,7 +320,7 @@ impl Value { process_int_config(value, &mut errors, &mut config.max_external_completion_results); } "completer" => { - if let Ok(v) = value.as_block() { + if let Ok(v) = value.coerce_block() { config.external_completer = Some(v) } else { match value { @@ -539,7 +539,7 @@ impl Value { process_bool_config(value, &mut errors, &mut config.filesize_metric); } "format" => { - if let Ok(v) = value.as_string() { + if let Ok(v) = value.coerce_string() { config.filesize_format = v.to_lowercase(); } else { report_invalid_value("should be a string", span, &mut errors); @@ -707,14 +707,14 @@ impl Value { let span = value.span(); match key2 { "normal" => { - if let Ok(v) = value.as_string() { + if let Ok(v) = value.coerce_string() { config.datetime_normal_format = Some(v); } else { report_invalid_value("should be a string", span, &mut errors); } } "table" => { - if let Ok(v) = value.as_string() { + if let Ok(v) = value.coerce_string() { config.datetime_table_format = Some(v); } else { report_invalid_value("should be a string", span, &mut errors); diff --git a/crates/nu-protocol/src/config/table.rs b/crates/nu-protocol/src/config/table.rs index 72083763e6..e9eee83482 100644 --- a/crates/nu-protocol/src/config/table.rs +++ b/crates/nu-protocol/src/config/table.rs @@ -251,7 +251,7 @@ pub(super) fn try_parse_trim_strategy( } TrimStrategy::Truncate { suffix } => { if let Some(value) = map.get("truncating_suffix") { - if let Ok(v) = value.as_string() { + if let Ok(v) = value.coerce_string() { *suffix = Some(v); } else { errors.push(ShellError::GenericError { @@ -272,7 +272,7 @@ pub(super) fn try_parse_trim_strategy( } fn try_parse_trim_methodology(value: &Value) -> Option { - if let Ok(value) = value.as_string() { + if let Ok(value) = value.coerce_string() { match value.to_lowercase().as_str() { "wrapping" => { return Some(TrimStrategy::Wrap { diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index 8647743438..a26a13cdbd 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -871,7 +871,7 @@ impl EngineState { pub fn get_cwd(&self) -> Option { if let Some(pwd_value) = self.get_env_var(PWD_ENV) { - pwd_value.as_string().ok() + pwd_value.coerce_string().ok() } else { None } @@ -900,7 +900,7 @@ impl EngineState { pub fn current_work_dir(&self) -> String { self.get_env_var("PWD") - .map(|d| d.as_string().unwrap_or_default()) + .map(|d| d.coerce_string().unwrap_or_default()) .unwrap_or_default() } diff --git a/crates/nu-protocol/src/engine/state_working_set.rs b/crates/nu-protocol/src/engine/state_working_set.rs index 4194585de7..1efebfc4ec 100644 --- a/crates/nu-protocol/src/engine/state_working_set.rs +++ b/crates/nu-protocol/src/engine/state_working_set.rs @@ -581,7 +581,8 @@ impl<'a> StateWorkingSet<'a> { .permanent_state .get_env_var(PWD_ENV) .expect("internal error: can't find PWD"); - pwd.as_string().expect("internal error: PWD not a string") + pwd.coerce_string() + .expect("internal error: PWD not a string") } pub fn get_env_var(&self, name: &str) -> Option<&Value> { diff --git a/crates/nu-protocol/src/eval_base.rs b/crates/nu-protocol/src/eval_base.rs index 4245acb809..0f5d8c8fa3 100644 --- a/crates/nu-protocol/src/eval_base.rs +++ b/crates/nu-protocol/src/eval_base.rs @@ -59,7 +59,7 @@ pub trait Eval { match item { RecordItem::Pair(col, val) => { // avoid duplicate cols - let col_name = Self::eval(state, mut_state, col)?.as_string()?; + let col_name = Self::eval(state, mut_state, col)?.coerce_into_string()?; if let Some(orig_span) = col_names.get(&col_name) { return Err(ShellError::ColumnDefinedTwice { col_name, @@ -102,7 +102,7 @@ pub trait Eval { Expr::Table(headers, vals) => { let mut output_headers = vec![]; for expr in headers { - let header = Self::eval(state, mut_state, expr)?.as_string()?; + let header = Self::eval(state, mut_state, expr)?.coerce_into_string()?; if let Some(idx) = output_headers .iter() .position(|existing| existing == &header) diff --git a/crates/nu-protocol/src/pipeline_data.rs b/crates/nu-protocol/src/pipeline_data.rs index 5ebb67a49a..72bf48be64 100644 --- a/crates/nu-protocol/src/pipeline_data.rs +++ b/crates/nu-protocol/src/pipeline_data.rs @@ -176,7 +176,7 @@ impl PipelineData { if s.is_binary { let mut output = vec![]; for item in items { - match item.as_binary() { + match item.coerce_into_binary() { Ok(item) => { output.extend(item); } @@ -192,7 +192,7 @@ impl PipelineData { } else { let mut output = String::new(); for item in items { - match item.as_string() { + match item.coerce_into_string() { Ok(s) => output.push_str(&s), Err(err) => { return Value::error(err, span); @@ -319,7 +319,7 @@ impl PipelineData { pub fn collect_string(self, separator: &str, config: &Config) -> Result { match self { PipelineData::Empty => Ok(String::new()), - PipelineData::Value(v, ..) => Ok(v.into_string(separator, config)), + PipelineData::Value(v, ..) => Ok(v.to_expanded_string(separator, config)), PipelineData::ListStream(s, ..) => Ok(s.into_string(separator, config)), PipelineData::ExternalStream { stdout: None, .. } => Ok(String::new()), PipelineData::ExternalStream { @@ -330,7 +330,7 @@ impl PipelineData { let mut output = String::new(); for val in s { - output.push_str(&val?.as_string()?); + output.push_str(&val?.coerce_into_string()?); } if trim_end_newline { output.truncate(output.trim_end_matches(LINE_ENDING_PATTERN).len()); @@ -783,9 +783,9 @@ impl PipelineData { is_err = true; format_error(&working_set, &*error) } else if no_newline { - item.into_string("", config) + item.to_expanded_string("", config) } else { - item.into_string("\n", config) + item.to_expanded_string("\n", config) }; if !no_newline { @@ -859,12 +859,12 @@ pub fn print_if_stream( if let Some(stream) = stream { for s in stream { let s_live = s?; - let bin_output = s_live.as_binary()?; + let bin_output = s_live.coerce_into_binary()?; if !to_stderr { - stdout_write_all_and_flush(bin_output)? + stdout_write_all_and_flush(&bin_output)? } else { - stderr_write_all_and_flush(bin_output)? + stderr_write_all_and_flush(&bin_output)? } } } diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 9c9a2ae2a8..85c1cce0ce 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -9,11 +9,9 @@ mod unit; pub mod record; -use crate::ast::{Bits, Boolean, CellPath, Comparison, PathMember}; -use crate::ast::{Math, Operator}; +use crate::ast::{Bits, Boolean, CellPath, Comparison, Math, Operator, PathMember, RangeInclusion}; use crate::engine::{Closure, EngineState}; -use crate::ShellError; -use crate::{did_you_mean, BlockId, Config, Span, Spanned, Type}; +use crate::{did_you_mean, BlockId, Config, ShellError, Span, Type}; use byte_unit::UnitType; use chrono::{DateTime, Datelike, Duration, FixedOffset, Locale, TimeZone}; @@ -236,278 +234,440 @@ impl Clone for Value { } impl Value { + fn cant_convert_to(&self, typ: &str) -> Result { + Err(ShellError::CantConvert { + to_type: typ.into(), + from_type: self.get_type().to_string(), + span: self.span(), + help: None, + }) + } + + /// Returns the inner `bool` value or an error if this `Value` is not a bool pub fn as_bool(&self) -> Result { - match self { - Value::Bool { val, .. } => Ok(*val), - x => Err(ShellError::CantConvert { - to_type: "boolean".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::Bool { val, .. } = self { + Ok(*val) + } else { + self.cant_convert_to("boolean") } } + /// Returns the inner `i64` value or an error if this `Value` is not an int pub fn as_int(&self) -> Result { - match self { - Value::Int { val, .. } => Ok(*val), - x => Err(ShellError::CantConvert { - to_type: "int".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::Int { val, .. } = self { + Ok(*val) + } else { + self.cant_convert_to("int") } } + /// Returns the inner `f64` value or an error if this `Value` is not a float pub fn as_float(&self) -> Result { + if let Value::Float { val, .. } = self { + Ok(*val) + } else { + self.cant_convert_to("float") + } + } + + /// Returns this `Value` converted to a `f64` or an error if it cannot be converted + /// + /// Only the following `Value` cases will return an `Ok` result: + /// - `Int` + /// - `Float` + /// + /// ``` + /// # use nu_protocol::Value; + /// for val in Value::test_values() { + /// assert_eq!( + /// matches!(val, Value::Float { .. } | Value::Int { .. }), + /// val.coerce_float().is_ok(), + /// ); + /// } + /// ``` + pub fn coerce_float(&self) -> Result { match self { Value::Float { val, .. } => Ok(*val), Value::Int { val, .. } => Ok(*val as f64), - x => Err(ShellError::CantConvert { - to_type: "float".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + val => val.cant_convert_to("float"), } } + /// Returns the inner `i64` filesize value or an error if this `Value` is not a filesize pub fn as_filesize(&self) -> Result { - match self { - Value::Filesize { val, .. } => Ok(*val), - x => Err(ShellError::CantConvert { - to_type: "filesize".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::Filesize { val, .. } = self { + Ok(*val) + } else { + self.cant_convert_to("filesize") } } + /// Returns the inner `i64` duration value or an error if this `Value` is not a duration pub fn as_duration(&self) -> Result { - match self { - Value::Duration { val, .. } => Ok(*val), - x => Err(ShellError::CantConvert { - to_type: "duration".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::Duration { val, .. } = self { + Ok(*val) + } else { + self.cant_convert_to("duration") } } + /// Returns the inner [`DateTime`] value or an error if this `Value` is not a date pub fn as_date(&self) -> Result, ShellError> { - match self { - Value::Date { val, .. } => Ok(*val), - x => Err(ShellError::CantConvert { - to_type: "date".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::Date { val, .. } = self { + Ok(*val) + } else { + self.cant_convert_to("date") } } + /// Returns a reference to the inner [`Range`] value or an error if this `Value` is not a range pub fn as_range(&self) -> Result<&Range, ShellError> { - match self { - Value::Range { val, .. } => Ok(val.as_ref()), - x => Err(ShellError::CantConvert { - to_type: "range".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::Range { val, .. } = self { + Ok(val.as_ref()) + } else { + self.cant_convert_to("range") } } - /// Converts into string values that can be changed into string natively - pub fn as_string(&self) -> Result { + /// Unwraps the inner [`Range`] value or returns an error if this `Value` is not a range + pub fn into_range(self) -> Result { + if let Value::Range { val, .. } = self { + Ok(*val) + } else { + self.cant_convert_to("range") + } + } + + /// Returns a reference to the inner `str` value or an error if this `Value` is not a string + pub fn as_str(&self) -> Result<&str, ShellError> { + if let Value::String { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("string") + } + } + + /// Unwraps the inner `String` value or returns an error if this `Value` is not a string + pub fn into_string(self) -> Result { + if let Value::String { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("string") + } + } + + /// Returns this `Value` converted to a `String` or an error if it cannot be converted + /// + /// Only the following `Value` cases will return an `Ok` result: + /// - `Int` + /// - `Float` + /// - `String` + /// - `Binary` (only if valid utf-8) + /// - `Date` + /// + /// Prefer [`coerce_into_string`](Self::coerce_into_string) + /// if you do not need to keep the original `Value` around. + /// + /// ``` + /// # use nu_protocol::Value; + /// for val in Value::test_values() { + /// assert_eq!( + /// matches!( + /// val, + /// Value::Int { .. } + /// | Value::Float { .. } + /// | Value::String { .. } + /// | Value::Binary { .. } + /// | Value::Date { .. } + /// ), + /// val.coerce_string().is_ok(), + /// ); + /// } + /// ``` + pub fn coerce_string(&self) -> Result { match self { Value::Int { val, .. } => Ok(val.to_string()), Value::Float { val, .. } => Ok(val.to_string()), - Value::String { val, .. } => Ok(val.to_string()), - Value::Binary { val, .. } => Ok(match std::str::from_utf8(val) { - Ok(s) => s.to_string(), - Err(_) => { - return Err(ShellError::CantConvert { - to_type: "string".into(), - from_type: "binary".into(), - span: self.span(), - help: None, - }); - } - }), + Value::String { val, .. } => Ok(val.clone()), + Value::Binary { val, .. } => match std::str::from_utf8(val) { + Ok(s) => Ok(s.to_string()), + Err(_) => self.cant_convert_to("string"), + }, Value::Date { val, .. } => Ok(val.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)), - x => Err(ShellError::CantConvert { - to_type: "string".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + val => val.cant_convert_to("string"), } } - pub fn as_spanned_string(&self) -> Result, ShellError> { + /// Returns this `Value` converted to a `String` or an error if it cannot be converted + /// + /// Only the following `Value` cases will return an `Ok` result: + /// - `Int` + /// - `Float` + /// - `String` + /// - `Binary` (only if valid utf-8) + /// - `Date` + /// + /// ``` + /// # use nu_protocol::Value; + /// for val in Value::test_values() { + /// assert_eq!( + /// matches!( + /// val, + /// Value::Int { .. } + /// | Value::Float { .. } + /// | Value::String { .. } + /// | Value::Binary { .. } + /// | Value::Date { .. } + /// ), + /// val.coerce_into_string().is_ok(), + /// ); + /// } + /// ``` + pub fn coerce_into_string(self) -> Result { let span = self.span(); match self { - Value::String { val, .. } => Ok(Spanned { - item: val.to_string(), - span, - }), - Value::Binary { val, .. } => Ok(match std::str::from_utf8(val) { - Ok(s) => Spanned { - item: s.to_string(), - span, - }, - Err(_) => { - return Err(ShellError::CantConvert { - to_type: "string".into(), - from_type: "binary".into(), - span: self.span(), - help: None, - }) - } - }), - x => Err(ShellError::CantConvert { - to_type: "string".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + Value::Int { val, .. } => Ok(val.to_string()), + Value::Float { val, .. } => Ok(val.to_string()), + Value::String { val, .. } => Ok(val), + Value::Binary { val, .. } => match String::from_utf8(val) { + Ok(s) => Ok(s), + Err(err) => Value::binary(err.into_bytes(), span).cant_convert_to("string"), + }, + Value::Date { val, .. } => Ok(val.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)), + val => val.cant_convert_to("string"), } } + /// Returns this `Value` as a `char` or an error if it is not a single character string pub fn as_char(&self) -> Result { let span = self.span(); - - match self { - Value::String { val, .. } => { - let mut chars = val.chars(); - match (chars.next(), chars.next()) { - (Some(c), None) => Ok(c), - _ => Err(ShellError::MissingParameter { - param_name: "single character separator".into(), - span, - }), - } + if let Value::String { val, .. } = self { + let mut chars = val.chars(); + match (chars.next(), chars.next()) { + (Some(c), None) => Ok(c), + _ => Err(ShellError::MissingParameter { + param_name: "single character separator".into(), + span, + }), } - x => Err(ShellError::CantConvert { - to_type: "char".into(), - from_type: x.get_type().to_string(), - span, - help: None, - }), + } else { + self.cant_convert_to("char") } } - pub fn as_path(&self) -> Result { - match self { - Value::String { val, .. } => Ok(PathBuf::from(val)), - x => Err(ShellError::CantConvert { - to_type: "path".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + /// Converts this `Value` to a `PathBuf` or returns an error if it is not a string + pub fn to_path(&self) -> Result { + if let Value::String { val, .. } = self { + Ok(PathBuf::from(val)) + } else { + self.cant_convert_to("path") } } + /// Returns a reference to the inner [`Record`] value or an error if this `Value` is not a record pub fn as_record(&self) -> Result<&Record, ShellError> { - match self { - Value::Record { val, .. } => Ok(val), - x => Err(ShellError::CantConvert { - to_type: "record".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::Record { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("record") } } + /// Unwraps the inner [`Record`] value or returns an error if this `Value` is not a record + pub fn into_record(self) -> Result { + if let Value::Record { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("record") + } + } + + /// Returns a reference to the inner list slice or an error if this `Value` is not a list pub fn as_list(&self) -> Result<&[Value], ShellError> { - match self { - Value::List { vals, .. } => Ok(vals), - x => Err(ShellError::CantConvert { - to_type: "list".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::List { vals, .. } = self { + Ok(vals) + } else { + self.cant_convert_to("list") } } + /// Unwraps the inner list `Vec` or returns an error if this `Value` is not a list + pub fn into_list(self) -> Result, ShellError> { + if let Value::List { vals, .. } = self { + Ok(vals) + } else { + self.cant_convert_to("list") + } + } + + /// Returns the inner [`BlockId`] or an error if this `Value` is not a block pub fn as_block(&self) -> Result { + if let Value::Block { val, .. } = self { + Ok(*val) + } else { + self.cant_convert_to("block") + } + } + + /// Returns this `Value`'s [`BlockId`] or an error if it does not have one + /// + /// Only the following `Value` cases will return an `Ok` result: + /// - `Block` + /// - `Closure` + /// + /// ``` + /// # use nu_protocol::Value; + /// for val in Value::test_values() { + /// assert_eq!( + /// matches!(val, Value::Block { .. } | Value::Closure { .. }), + /// val.coerce_block().is_ok(), + /// ); + /// } + /// ``` + pub fn coerce_block(&self) -> Result { match self { Value::Block { val, .. } => Ok(*val), Value::Closure { val, .. } => Ok(val.block_id), - x => Err(ShellError::CantConvert { - to_type: "block".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + val => val.cant_convert_to("block"), } } + /// Returns a reference to the inner [`Closure`] value or an error if this `Value` is not a closure pub fn as_closure(&self) -> Result<&Closure, ShellError> { - match self { - Value::Closure { val, .. } => Ok(val), - x => Err(ShellError::CantConvert { - to_type: "closure".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::Closure { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("closure") } } + /// Unwraps the inner [`Closure`] value or returns an error if this `Value` is not a closure + pub fn into_closure(self) -> Result { + if let Value::Closure { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("closure") + } + } + + /// Returns a reference to the inner binary slice or an error if this `Value` is not a binary value pub fn as_binary(&self) -> Result<&[u8], ShellError> { + if let Value::Binary { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("binary") + } + } + + /// Unwraps the inner binary `Vec` or returns an error if this `Value` is not a binary value + pub fn into_binary(self) -> Result, ShellError> { + if let Value::Binary { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("binary") + } + } + + /// Returns this `Value` as a `u8` slice or an error if it cannot be converted + /// + /// Only the following `Value` cases will return an `Ok` result: + /// - `Binary` + /// - `String` + /// + /// Prefer [`coerce_into_binary`](Self::coerce_into_binary) + /// if you do not need to keep the original `Value` around. + /// + /// ``` + /// # use nu_protocol::Value; + /// for val in Value::test_values() { + /// assert_eq!( + /// matches!(val, Value::Binary { .. } | Value::String { .. }), + /// val.coerce_binary().is_ok(), + /// ); + /// } + /// ``` + pub fn coerce_binary(&self) -> Result<&[u8], ShellError> { match self { Value::Binary { val, .. } => Ok(val), Value::String { val, .. } => Ok(val.as_bytes()), - x => Err(ShellError::CantConvert { - to_type: "binary".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + val => val.cant_convert_to("binary"), } } + /// Returns this `Value` as a `Vec` or an error if it cannot be converted + /// + /// Only the following `Value` cases will return an `Ok` result: + /// - `Binary` + /// - `String` + /// + /// ``` + /// # use nu_protocol::Value; + /// for val in Value::test_values() { + /// assert_eq!( + /// matches!(val, Value::Binary { .. } | Value::String { .. }), + /// val.coerce_into_binary().is_ok(), + /// ); + /// } + /// ``` + pub fn coerce_into_binary(self) -> Result, ShellError> { + match self { + Value::Binary { val, .. } => Ok(val), + Value::String { val, .. } => Ok(val.into_bytes()), + val => val.cant_convert_to("binary"), + } + } + + /// Returns a reference to the inner [`CellPath`] value or an error if this `Value` is not a cell path pub fn as_cell_path(&self) -> Result<&CellPath, ShellError> { - match self { - Value::CellPath { val, .. } => Ok(val), - x => Err(ShellError::CantConvert { - to_type: "cell path".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::CellPath { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("cell path") } } + /// Unwraps the inner [`CellPath`] value or returns an error if this `Value` is not a cell path + pub fn into_cell_path(self) -> Result { + if let Value::CellPath { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("cell path") + } + } + + /// Returns a reference to the inner [`CustomValue`] trait object or an error if this `Value` is not a custom value pub fn as_custom_value(&self) -> Result<&dyn CustomValue, ShellError> { - match self { - Value::CustomValue { val, .. } => Ok(val.as_ref()), - x => Err(ShellError::CantConvert { - to_type: "custom value".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + if let Value::CustomValue { val, .. } = self { + Ok(val.as_ref()) + } else { + self.cant_convert_to("custom value") } } + /// Unwraps the inner [`CustomValue`] trait object or returns an error if this `Value` is not a custom value + pub fn into_custom_value(self) -> Result, ShellError> { + if let Value::CustomValue { val, .. } = self { + Ok(val) + } else { + self.cant_convert_to("custom 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> { - match self { - Value::LazyRecord { val, .. } => Ok(val.as_ref()), - x => Err(ShellError::CantConvert { - to_type: "lazy record".into(), - from_type: x.get_type().to_string(), - span: self.span(), - help: None, - }), + 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") } } @@ -642,142 +802,6 @@ impl Value { } } - // Convert Value into String, but propagate errors. - pub fn nonerror_into_string( - &self, - separator: &str, - config: &Config, - ) -> Result { - if let Value::Error { error, .. } = self { - Err(*error.to_owned()) - } else { - Ok(self.into_string(separator, config)) - } - } - - /// Convert Value into string. Note that Streams will be consumed. - pub fn into_string(&self, separator: &str, config: &Config) -> String { - let span = self.span(); - - match self { - Value::Bool { val, .. } => val.to_string(), - Value::Int { val, .. } => val.to_string(), - Value::Float { val, .. } => val.to_string(), - Value::Filesize { val, .. } => format_filesize_from_conf(*val, config), - Value::Duration { val, .. } => format_duration(*val), - - Value::Date { val, .. } => match &config.datetime_normal_format { - Some(format) => self.format_datetime(val, format), - None => { - format!( - "{} ({})", - if val.year() >= 0 { - val.to_rfc2822() - } else { - val.to_rfc3339() - }, - HumanTime::from(*val), - ) - } - }, - Value::Range { val, .. } => { - format!( - "{}..{}", - val.from.into_string(", ", config), - val.to.into_string(", ", config) - ) - } - Value::String { val, .. } => val.clone(), - Value::QuotedString { val, .. } => val.clone(), - Value::List { vals: val, .. } => format!( - "[{}]", - val.iter() - .map(|x| x.into_string(", ", config)) - .collect::>() - .join(separator) - ), - Value::Record { val, .. } => format!( - "{{{}}}", - val.iter() - .map(|(x, y)| format!("{}: {}", x, y.into_string(", ", config))) - .collect::>() - .join(separator) - ), - Value::LazyRecord { val, .. } => { - let collected = match val.collect() { - Ok(val) => val, - Err(error) => Value::Error { - error: Box::new(error), - internal_span: span, - }, - }; - collected.into_string(separator, config) - } - Value::Block { val, .. } => format!(""), - Value::Closure { val, .. } => format!("", val.block_id), - Value::Nothing { .. } => String::new(), - Value::Error { error, .. } => format!("{error:?}"), - Value::Binary { val, .. } => format!("{val:?}"), - Value::CellPath { val, .. } => val.to_string(), - Value::CustomValue { val, .. } => val.value_string(), - } - } - - /// Convert Value into string. Note that Streams will be consumed. - pub fn into_abbreviated_string(&self, config: &Config) -> String { - match self { - Value::Bool { val, .. } => val.to_string(), - Value::Int { val, .. } => val.to_string(), - Value::Float { val, .. } => val.to_string(), - Value::Filesize { val, .. } => format_filesize_from_conf(*val, config), - Value::Duration { val, .. } => format_duration(*val), - Value::Date { val, .. } => match &config.datetime_table_format { - Some(format) => self.format_datetime(val, format), - None => HumanTime::from(*val).to_string(), - }, - Value::Range { val, .. } => { - format!( - "{}..{}", - val.from.into_string(", ", config), - val.to.into_string(", ", config) - ) - } - Value::String { val, .. } => val.to_string(), - Value::QuotedString { val, .. } => val.to_string(), - Value::List { ref vals, .. } => { - if !vals.is_empty() && vals.iter().all(|x| matches!(x, Value::Record { .. })) { - format!( - "[table {} row{}]", - vals.len(), - if vals.len() == 1 { "" } else { "s" } - ) - } else { - format!( - "[list {} item{}]", - vals.len(), - if vals.len() == 1 { "" } else { "s" } - ) - } - } - Value::Record { val, .. } => format!( - "{{record {} field{}}}", - val.len(), - if val.len() == 1 { "" } else { "s" } - ), - Value::LazyRecord { val, .. } => match val.collect() { - Ok(val) => val.into_abbreviated_string(config), - Err(error) => format!("{error:?}"), - }, - Value::Block { val, .. } => format!(""), - Value::Closure { val, .. } => format!("", val.block_id), - Value::Nothing { .. } => String::new(), - Value::Error { error, .. } => format!("{error:?}"), - Value::Binary { val, .. } => format!("{val:?}"), - Value::CellPath { val, .. } => val.to_string(), - Value::CustomValue { val, .. } => val.value_string(), - } - } - fn format_datetime(&self, date_time: &DateTime, formatter: &str) -> String where Tz::Offset: Display, @@ -806,8 +830,149 @@ impl Value { formatter_buf } - /// Convert Value into a debug string - pub fn debug_value(&self) -> String { + /// Converts this `Value` to a string according to the given [`Config`] and separator + /// + /// This functions recurses into records and lists, + /// returning a string that contains the stringified form of all nested `Value`s. + pub fn to_expanded_string(&self, separator: &str, config: &Config) -> String { + let span = self.span(); + match self { + Value::Bool { val, .. } => val.to_string(), + Value::Int { val, .. } => val.to_string(), + Value::Float { val, .. } => val.to_string(), + Value::Filesize { val, .. } => format_filesize_from_conf(*val, config), + Value::Duration { val, .. } => format_duration(*val), + Value::Date { val, .. } => match &config.datetime_normal_format { + Some(format) => self.format_datetime(val, format), + None => { + format!( + "{} ({})", + if val.year() >= 0 { + val.to_rfc2822() + } else { + val.to_rfc3339() + }, + HumanTime::from(*val), + ) + } + }, + Value::Range { val, .. } => { + format!( + "{}..{}", + val.from.to_expanded_string(", ", config), + val.to.to_expanded_string(", ", config) + ) + } + Value::String { val, .. } => val.clone(), + Value::QuotedString { val, .. } => val.clone(), + Value::List { vals: val, .. } => format!( + "[{}]", + val.iter() + .map(|x| x.to_expanded_string(", ", config)) + .collect::>() + .join(separator) + ), + Value::Record { val, .. } => format!( + "{{{}}}", + val.iter() + .map(|(x, y)| format!("{}: {}", x, y.to_expanded_string(", ", config))) + .collect::>() + .join(separator) + ), + Value::LazyRecord { val, .. } => val + .collect() + .unwrap_or_else(|err| Value::error(err, span)) + .to_expanded_string(separator, config), + Value::Block { val, .. } => format!(""), + Value::Closure { val, .. } => format!("", val.block_id), + Value::Nothing { .. } => String::new(), + Value::Error { error, .. } => format!("{error:?}"), + Value::Binary { val, .. } => format!("{val:?}"), + Value::CellPath { val, .. } => val.to_string(), + Value::CustomValue { val, .. } => val.value_string(), + } + } + + /// Converts this `Value` to a string according to the given [`Config`] + /// + /// This functions does not recurse into records and lists. + /// Instead, it will shorten the first list or record it finds like so: + /// - "[table {n} rows]" + /// - "[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), + None => HumanTime::from(*val).to_string(), + }, + Value::List { ref vals, .. } => { + if !vals.is_empty() && vals.iter().all(|x| matches!(x, Value::Record { .. })) { + format!( + "[table {} row{}]", + vals.len(), + if vals.len() == 1 { "" } else { "s" } + ) + } else { + format!( + "[list {} item{}]", + vals.len(), + if vals.len() == 1 { "" } else { "s" } + ) + } + } + Value::Record { val, .. } => format!( + "{{record {} field{}}}", + 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), + } + } + + /// Converts this `Value` to a string according to the given [`Config`] and separator + /// + /// This function adds quotes around strings, + /// so that the returned string can be parsed by nushell. + /// The other `Value` cases are already parsable when converted strings + /// or are not yet handled by this function. + /// + /// This functions behaves like [`to_formatted_string`](Self::to_formatted_string) + /// and will recurse into records and lists. + pub fn to_parsable_string(&self, separator: &str, config: &Config) -> String { + match self { + // give special treatment to the simple types to make them parsable + Value::String { val, .. } => format!("'{}'", val), + // recurse back into this function for recursive formatting + Value::List { vals: val, .. } => format!( + "[{}]", + val.iter() + .map(|x| x.to_parsable_string(", ", config)) + .collect::>() + .join(separator) + ), + Value::Record { val, .. } => format!( + "{{{}}}", + val.iter() + .map(|(x, y)| format!("{}: {}", x, y.to_parsable_string(", ", config))) + .collect::>() + .join(separator) + ), + // defer to standard handling for types where standard representation is parsable + _ => self.to_expanded_string(separator, config), + } + } + + /// Convert this `Value` to a debug string + /// + /// In general, this function should only be used for debug purposes, + /// and the resulting string should not be displayed to the user (not even in an error). + pub fn to_debug_string(&self) -> String { match self { Value::String { val, .. } => { if contains_emoji(val) { @@ -824,81 +989,6 @@ impl Value { } } - /// Convert Value into a parsable string (quote strings) - /// bugbug other, rarer types not handled - - pub fn into_string_parsable(&self, separator: &str, config: &Config) -> String { - match self { - // give special treatment to the simple types to make them parsable - Value::String { val, .. } => format!("'{}'", val), - - // recurse back into this function for recursive formatting - Value::List { vals: val, .. } => format!( - "[{}]", - val.iter() - .map(|x| x.into_string_parsable(", ", config)) - .collect::>() - .join(separator) - ), - Value::Record { val, .. } => format!( - "{{{}}}", - val.iter() - .map(|(x, y)| format!("{}: {}", x, y.into_string_parsable(", ", config))) - .collect::>() - .join(separator) - ), - - // defer to standard handling for types where standard representation is parsable - _ => self.into_string(separator, config), - } - } - - /// Convert Value into string. Note that Streams will be consumed. - pub fn debug_string(&self, separator: &str, config: &Config) -> String { - match self { - Value::Bool { val, .. } => val.to_string(), - Value::Int { val, .. } => val.to_string(), - Value::Float { val, .. } => val.to_string(), - Value::Filesize { val, .. } => format_filesize_from_conf(*val, config), - Value::Duration { val, .. } => format_duration(*val), - Value::Date { val, .. } => format!("{val:?}"), - Value::Range { val, .. } => { - format!( - "{}..{}", - val.from.into_string(", ", config), - val.to.into_string(", ", config) - ) - } - Value::String { val, .. } => val.clone(), - Value::QuotedString { val, .. } => val.clone(), - Value::List { vals: val, .. } => format!( - "[{}]", - val.iter() - .map(|x| x.into_string(", ", config)) - .collect::>() - .join(separator) - ), - Value::Record { val, .. } => format!( - "{{{}}}", - val.iter() - .map(|(x, y)| format!("{}: {}", x, y.into_string(", ", config))) - .collect::>() - .join(separator) - ), - Value::LazyRecord { val, .. } => match val.collect() { - Ok(val) => val.debug_string(separator, config), - Err(error) => format!("{error:?}"), - }, - Value::Block { val, .. } => format!(""), - Value::Closure { val, .. } => format!("", val.block_id), - Value::Nothing { .. } => String::new(), - Value::Error { error, .. } => format!("{error:?}"), - Value::Binary { val, .. } => format!("{val:?}"), - Value::CellPath { val, .. } => val.to_string(), - Value::CustomValue { val, .. } => val.value_string(), - } - } - /// Follow a given cell path into the value: for example accessing select elements in a stream or list pub fn follow_cell_path( self, @@ -1940,6 +2030,47 @@ impl Value { 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`. + pub fn test_values() -> Vec { + vec![ + Value::test_bool(false), + Value::test_int(0), + Value::test_filesize(0), + Value::test_duration(0), + Value::test_date(DateTime::UNIX_EPOCH.into()), + Value::test_range(Range { + from: Value::test_nothing(), + incr: Value::test_nothing(), + to: Value::test_nothing(), + inclusion: RangeInclusion::Inclusive, + }), + 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_block(0), + Value::test_closure(Closure { + block_id: 0, + captures: Vec::new(), + }), + Value::test_nothing(), + Value::error( + ShellError::NushellFailed { msg: String::new() }, + Span::test_data(), + ), + Value::test_binary(Vec::new()), + Value::test_cell_path(CellPath { + members: Vec::new(), + }), + // Value::test_custom_value(Box::new(todo!())), + ] + } } impl Default for Value { @@ -3869,7 +4000,7 @@ mod tests { NaiveDateTime::from_timestamp_millis(-123456789).unwrap(), FixedOffset::east_opt(0).unwrap(), )) - .into_string("", &Default::default()); + .to_expanded_string("", &Default::default()); // We need to cut the humanized part off for tests to work, because // it is relative to current time. @@ -3883,7 +4014,7 @@ mod tests { NaiveDateTime::from_timestamp_millis(-72135596800000).unwrap(), FixedOffset::east_opt(0).unwrap(), )) - .into_string("", &Default::default()); + .to_expanded_string("", &Default::default()); // We need to cut the humanized part off for tests to work, because // it is relative to current time. diff --git a/crates/nu-protocol/src/value/stream.rs b/crates/nu-protocol/src/value/stream.rs index 4118b24eef..58e759229b 100644 --- a/crates/nu-protocol/src/value/stream.rs +++ b/crates/nu-protocol/src/value/stream.rs @@ -55,7 +55,7 @@ impl RawStream { if nu_utils::ctrl_c::was_pressed(ctrlc) { break; } - output.push_str(&item?.as_string()?); + output.push_str(&item?.coerce_into_string()?); } Ok(Spanned { item: output, span }) @@ -189,7 +189,7 @@ pub struct ListStream { impl ListStream { pub fn into_string(self, separator: &str, config: &Config) -> String { - self.map(|x: Value| x.into_string(", ", config)) + self.map(|x: Value| x.to_expanded_string(", ", config)) .collect::>() .join(separator) } diff --git a/crates/nu-protocol/tests/test_value.rs b/crates/nu-protocol/tests/test_value.rs index 0766657ba7..376bd81f1f 100644 --- a/crates/nu-protocol/tests/test_value.rs +++ b/crates/nu-protocol/tests/test_value.rs @@ -42,7 +42,7 @@ fn test_duration_to_string(#[case] in_ns: i64, #[case] expected: &str) { let dur = Value::test_duration(in_ns); assert_eq!( expected, - dur.into_string("", &Config::default()), + dur.to_expanded_string("", &Config::default()), "expected != observed" ); } diff --git a/crates/nu-table/src/common.rs b/crates/nu-table/src/common.rs index 9e80d07ec5..67095b5c79 100644 --- a/crates/nu-table/src/common.rs +++ b/crates/nu-table/src/common.rs @@ -47,7 +47,7 @@ pub fn nu_value_to_string_colored(val: &Value, cfg: &Config, style: &StyleComput pub fn nu_value_to_string(val: &Value, cfg: &Config, style: &StyleComputer) -> NuText { let float_precision = cfg.float_precision as usize; - let text = val.into_abbreviated_string(cfg); + let text = val.to_abbreviated_string(cfg); make_styled_string(style, text, Some(val), float_precision) } @@ -99,7 +99,7 @@ pub fn get_value_style(value: &Value, config: &Config, style_computer: &StyleCom style_computer.style_primitive(value), ), _ => ( - value.into_abbreviated_string(config), + value.to_abbreviated_string(config), style_computer.style_primitive(value), ), } diff --git a/crates/nu-table/src/types/expanded.rs b/crates/nu-table/src/types/expanded.rs index e074b947dc..0be50eee56 100644 --- a/crates/nu-table/src/types/expanded.rs +++ b/crates/nu-table/src/types/expanded.rs @@ -118,7 +118,7 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { .as_record() .ok() .and_then(|val| val.get(INDEX_COLUMN_NAME)) - .map(|value| value.into_string("", cfg.opts.config)) + .map(|value| value.to_expanded_string("", cfg.opts.config)) .unwrap_or_else(|| index.to_string()); let row = row + with_header as usize; diff --git a/crates/nu-table/src/types/general.rs b/crates/nu-table/src/types/general.rs index 9171f6c1a1..c74b5bbf0a 100644 --- a/crates/nu-table/src/types/general.rs +++ b/crates/nu-table/src/types/general.rs @@ -207,7 +207,7 @@ fn get_table_row_index(item: &Value, config: &Config, row: usize, offset: usize) match item { Value::Record { val, .. } => val .get(INDEX_COLUMN_NAME) - .map(|value| value.into_string("", config)) + .map(|value| value.to_expanded_string("", config)) .unwrap_or_else(|| (row + offset).to_string()), _ => (row + offset).to_string(), } diff --git a/crates/nu-table/src/unstructured_table.rs b/crates/nu-table/src/unstructured_table.rs index 4ae7d35b1f..1330508fb6 100644 --- a/crates/nu-table/src/unstructured_table.rs +++ b/crates/nu-table/src/unstructured_table.rs @@ -100,7 +100,7 @@ fn convert_nu_value_to_table_value(value: Value, config: &Config) -> TableValue } } value => { - let mut text = value.into_abbreviated_string(config); + let mut text = value.to_abbreviated_string(config); if string_width(&text) > 50 { text = string_wrap(&text, 30, false); } diff --git a/crates/nu_plugin_formats/src/from/eml.rs b/crates/nu_plugin_formats/src/from/eml.rs index 296cbad81e..8ce2dc1af3 100644 --- a/crates/nu_plugin_formats/src/from/eml.rs +++ b/crates/nu_plugin_formats/src/from/eml.rs @@ -97,7 +97,7 @@ fn headerfieldvalue_to_value(head: Span, value: &HeaderFieldValue) -> Value { } fn from_eml(input: &Value, body_preview: usize, head: Span) -> Result { - let value = input.as_string()?; + let value = input.coerce_string()?; let eml = EmlParser::from_string(value) .with_body_preview(body_preview) diff --git a/crates/nu_plugin_formats/src/from/ics.rs b/crates/nu_plugin_formats/src/from/ics.rs index 7509deddab..ee6e15350b 100644 --- a/crates/nu_plugin_formats/src/from/ics.rs +++ b/crates/nu_plugin_formats/src/from/ics.rs @@ -9,7 +9,7 @@ pub const CMD_NAME: &str = "from ics"; pub fn from_ics_call(call: &EvaluatedCall, input: &Value) -> Result { let span = input.span(); - let input_string = input.as_string()?; + let input_string = input.coerce_string()?; let head = call.head; let input_string = input_string diff --git a/crates/nu_plugin_formats/src/from/ini.rs b/crates/nu_plugin_formats/src/from/ini.rs index 74a885b998..80be81ba7b 100644 --- a/crates/nu_plugin_formats/src/from/ini.rs +++ b/crates/nu_plugin_formats/src/from/ini.rs @@ -5,7 +5,7 @@ pub const CMD_NAME: &str = "from ini"; pub fn from_ini_call(call: &EvaluatedCall, input: &Value) -> Result { let span = input.span(); - let input_string = input.as_string()?; + let input_string = input.coerce_string()?; let head = call.head; let ini_config: Result = ini::Ini::load_from_str(&input_string); diff --git a/crates/nu_plugin_formats/src/from/vcf.rs b/crates/nu_plugin_formats/src/from/vcf.rs index c44aebb9d3..ebfb12b3ae 100644 --- a/crates/nu_plugin_formats/src/from/vcf.rs +++ b/crates/nu_plugin_formats/src/from/vcf.rs @@ -8,7 +8,7 @@ pub const CMD_NAME: &str = "from vcf"; pub fn from_vcf_call(call: &EvaluatedCall, input: &Value) -> Result { let span = input.span(); - let input_string = input.as_string()?; + let input_string = input.coerce_string()?; let head = call.head; let input_string = input_string diff --git a/crates/nu_plugin_gstat/src/gstat.rs b/crates/nu_plugin_gstat/src/gstat.rs index 61ae11bad1..96abb64a04 100644 --- a/crates/nu_plugin_gstat/src/gstat.rs +++ b/crates/nu_plugin_gstat/src/gstat.rs @@ -38,7 +38,7 @@ impl GStat { let mut using_input_value = false; // let's get the input value as a string - let piped_value = match value.as_string() { + let piped_value = match value.coerce_string() { Ok(s) => { using_input_value = true; s diff --git a/crates/nu_plugin_inc/src/inc.rs b/crates/nu_plugin_inc/src/inc.rs index 7bfa92cf25..894dd1368c 100644 --- a/crates/nu_plugin_inc/src/inc.rs +++ b/crates/nu_plugin_inc/src/inc.rs @@ -119,7 +119,7 @@ impl Inc { Value::Int { val, .. } => Ok(Value::int(val + 1, head)), Value::String { val, .. } => Ok(self.apply(val, head)), x => { - let msg = x.as_string().map_err(|e| LabeledError { + let msg = x.coerce_string().map_err(|e| LabeledError { label: "Unable to extract string".into(), msg: format!("value cannot be converted to string {x:?} - {e}"), span: Some(head), diff --git a/crates/nu_plugin_query/src/query_json.rs b/crates/nu_plugin_query/src/query_json.rs index 52af64c474..2c2caae8d0 100644 --- a/crates/nu_plugin_query/src/query_json.rs +++ b/crates/nu_plugin_query/src/query_json.rs @@ -8,7 +8,7 @@ pub fn execute_json_query( input: &Value, query: Option>, ) -> Result { - let input_string = match &input.as_string() { + let input_string = match &input.coerce_string() { Ok(s) => s.clone(), Err(e) => { return Err(LabeledError { diff --git a/crates/nu_plugin_query/src/query_web.rs b/crates/nu_plugin_query/src/query_web.rs index ad6eca4f97..7ae8cddc5e 100644 --- a/crates/nu_plugin_query/src/query_web.rs +++ b/crates/nu_plugin_query/src/query_web.rs @@ -318,7 +318,7 @@ mod tests { Span::test_data(), ); let config = nu_protocol::Config::default(); - let out = item.into_string("\n", &config); + let out = item.to_expanded_string("\n", &config); assert_eq!("[[Coffee]]".to_string(), out) } @@ -340,7 +340,7 @@ mod tests { .as_list() .unwrap() .iter() - .map(|text_nodes| text_nodes.as_string().unwrap()) + .map(|text_nodes| text_nodes.coerce_string().unwrap()) .collect::>() }) .collect::>>(); diff --git a/crates/nu_plugin_query/src/query_xml.rs b/crates/nu_plugin_query/src/query_xml.rs index fe48f27b99..fb80b71263 100644 --- a/crates/nu_plugin_query/src/query_xml.rs +++ b/crates/nu_plugin_query/src/query_xml.rs @@ -21,7 +21,7 @@ pub fn execute_xpath_query( }; let xpath = build_xpath(query_string, span)?; - let input_string = input.as_string()?; + let input_string = input.coerce_string()?; let package = parser::parse(&input_string); if package.is_err() { diff --git a/src/test_bins.rs b/src/test_bins.rs index 75f13ed382..597808dba6 100644 --- a/src/test_bins.rs +++ b/src/test_bins.rs @@ -325,7 +325,7 @@ pub fn nu_repl() { if let Some(cwd) = stack.get_env_var(&engine_state, "PWD") { let path = cwd - .as_string() + .coerce_string() .unwrap_or_else(|err| outcome_err(&engine_state, &err)); let _ = std::env::set_current_dir(path); engine_state.add_env_var("PWD".into(), cwd);