From f0e93c2fa97979c37c2a4e50a6edc0124ea1382e Mon Sep 17 00:00:00 2001 From: Kangaxx-0 <85712372+Kangaxx-0@users.noreply.github.com> Date: Sat, 10 Dec 2022 05:26:42 -0800 Subject: [PATCH] into cellpath command (#7417) # Description Address part of feature request #7337, add a small command `into cellpath` to allow string -> cellpath auto-conversion, with this change, we could run ``` let p = 'ls.use_ls_colors' $env.config | upsert ($p | nito cellpath) false ``` image Note - This pr only covers `String` -> `CellPath`, any other conversions should be considered as expected? # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - [x] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - [x] `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. --- .../src/conversions/into/cellpath.rs | 121 ++++++++++++++++++ crates/nu-command/src/conversions/into/mod.rs | 2 + crates/nu-command/src/default_context.rs | 1 + .../tests/commands/into_cellpath.rs | 14 ++ crates/nu-command/tests/commands/mod.rs | 1 + src/tests.rs | 21 +++ src/tests/test_env.rs | 10 ++ 7 files changed, 170 insertions(+) create mode 100644 crates/nu-command/src/conversions/into/cellpath.rs create mode 100644 crates/nu-command/tests/commands/into_cellpath.rs diff --git a/crates/nu-command/src/conversions/into/cellpath.rs b/crates/nu-command/src/conversions/into/cellpath.rs new file mode 100644 index 0000000000..a0e035f094 --- /dev/null +++ b/crates/nu-command/src/conversions/into/cellpath.rs @@ -0,0 +1,121 @@ +use nu_protocol::ast::{CellPath, PathMember}; + +use nu_protocol::{ + ast::Call, + engine::{Command, EngineState, Stack}, + Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value, +}; +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "into cellpath" + } + + fn signature(&self) -> Signature { + Signature::build("into cellpath") + .input_output_types(vec![(Type::String, Type::CellPath)]) + .category(Category::Conversions) + } + + fn usage(&self) -> &str { + "Convert value to a cellpath." + } + + fn search_terms(&self) -> Vec<&str> { + vec!["convert"] + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + into_cellpath(engine_state, call, input) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Convert from string to cellpath", + example: " 'config.show_banner' | into cellpath", + result: Some(Value::CellPath { + val: CellPath { + members: vec![ + PathMember::String { + val: "config".to_string(), + span: Span::new(1, 21), + }, + PathMember::String { + val: "show_banner".to_string(), + span: Span::new(1, 21), + }, + ], + }, + span: Span::new(1, 21), + }), + }, + Example { + description: "Convert from string to cellpath", + example: " 'a' | into cellpath", + result: Some(Value::CellPath { + val: CellPath { + members: vec![PathMember::String { + val: "a".to_string(), + span: Span::new(38, 41), + }], + }, + span: Span::new(1, 2), + }), + }, + ] + } +} + +fn into_cellpath( + _: &EngineState, + call: &Call, + input: PipelineData, +) -> Result { + let input = input.into_value(call.head); + let res = match input { + Value::String { val, span } => parse_string_into_cellapth(val, span), + other => Value::Error { + error: ShellError::UnsupportedInput( + "'into cellpath' does not support this input".into(), + other.span().unwrap_or(call.head), + ), + }, + }; + Ok(res.into_pipeline_data()) +} + +fn parse_string_into_cellapth(val: String, span: Span) -> Value { + let parts = val.split('.').collect::>(); + let mut cellpath: Vec = vec![]; + for part in parts { + cellpath.push(PathMember::String { + val: part.to_string(), + span, + }) + } + Value::CellPath { + val: CellPath { members: cellpath }, + span, + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/conversions/into/mod.rs b/crates/nu-command/src/conversions/into/mod.rs index ee0ad71d5c..cbe562b840 100644 --- a/crates/nu-command/src/conversions/into/mod.rs +++ b/crates/nu-command/src/conversions/into/mod.rs @@ -1,5 +1,6 @@ mod binary; mod bool; +mod cellpath; mod command; mod datetime; mod decimal; @@ -12,6 +13,7 @@ mod string; pub use self::bool::SubCommand as IntoBool; pub use self::filesize::SubCommand as IntoFilesize; pub use binary::SubCommand as IntoBinary; +pub use cellpath::SubCommand as IntoCellPath; pub use command::Into; pub use datetime::SubCommand as IntoDatetime; pub use decimal::SubCommand as IntoDecimal; diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 70b6462f15..6dd0f6e2e6 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -370,6 +370,7 @@ pub fn create_default_context() -> EngineState { IntoDuration, IntoFilesize, IntoInt, + IntoCellPath, IntoRecord, IntoString, }; diff --git a/crates/nu-command/tests/commands/into_cellpath.rs b/crates/nu-command/tests/commands/into_cellpath.rs new file mode 100644 index 0000000000..94b0b19f83 --- /dev/null +++ b/crates/nu-command/tests/commands/into_cellpath.rs @@ -0,0 +1,14 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn into_pathcell_string() { + let actual = nu!( + cwd: ".", pipeline( + r#" + 'nu.is.awesome' | into cellpath + "# + )); + dbg!(&actual.out); + + assert!(actual.out.contains("nu.is.awesome")); +} diff --git a/crates/nu-command/tests/commands/mod.rs b/crates/nu-command/tests/commands/mod.rs index 3f89a8cffa..3740beb522 100644 --- a/crates/nu-command/tests/commands/mod.rs +++ b/crates/nu-command/tests/commands/mod.rs @@ -34,6 +34,7 @@ mod headers; mod help; mod histogram; mod insert; +mod into_cellpath; mod into_filesize; mod into_int; mod last; diff --git a/src/tests.rs b/src/tests.rs index b5f5c2e8ae..fc4ba64b5c 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -25,6 +25,8 @@ use tempfile::NamedTempFile; pub type TestResult = Result<(), Box>; +const DEFAULT_CONFIG: &str = "./crates/nu-utils/src/sample_config/default_config.nu"; + pub fn run_test_with_env(input: &str, expected: &str, env: &HashMap<&str, &str>) -> TestResult { let mut file = NamedTempFile::new()?; let name = file.path(); @@ -54,6 +56,25 @@ pub fn run_test(input: &str, expected: &str) -> TestResult { run_cmd_and_assert(cmd, expected) } +#[cfg(test)] +pub fn run_test_with_default_config(input: &str, expected: &str) -> TestResult { + let mut file = NamedTempFile::new()?; + let name = file.path(); + + let mut cmd = Command::cargo_bin("nu")?; + cmd.arg("--config"); + cmd.arg(DEFAULT_CONFIG); + cmd.arg(name); + cmd.env( + "PWD", + std::env::current_dir().expect("Can't get current dir"), + ); + + writeln!(file, "{}", input)?; + + run_cmd_and_assert(cmd, expected) +} + #[cfg(test)] fn run_cmd_and_assert(mut cmd: Command, expected: &str) -> TestResult { let output = cmd.output()?; diff --git a/src/tests/test_env.rs b/src/tests/test_env.rs index 23f2aaf42d..95b248017a 100644 --- a/src/tests/test_env.rs +++ b/src/tests/test_env.rs @@ -1,5 +1,7 @@ use crate::tests::{run_test, TestResult}; +use super::run_test_with_default_config; + #[test] fn shorthand_env_1() -> TestResult { run_test(r#"FOO=BAZ $env.FOO"#, "BAZ") @@ -22,3 +24,11 @@ fn convert_non_string_env_var_to_nothing() -> TestResult { "nothing", ) } + +#[test] +fn convert_string_to_env_var_cellpath() -> TestResult { + run_test_with_default_config( + r#"let p = 'ls.use_ls_colors'; $env.config | upsert ($p | into cellpath) false | get ls.use_ls_colors"#, + "false", + ) +}