forked from extern/nushell
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 ``` <img width="710" alt="image" src="https://user-images.githubusercontent.com/85712372/206782818-3024b34f-150b-482d-aebc-9426ef6a1cf9.png"> 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.
This commit is contained in:
parent
fa6bb147ea
commit
f0e93c2fa9
121
crates/nu-command/src/conversions/into/cellpath.rs
Normal file
121
crates/nu-command/src/conversions/into/cellpath.rs
Normal file
@ -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<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
into_cellpath(engine_state, call, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
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<PipelineData, ShellError> {
|
||||||
|
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::<Vec<&str>>();
|
||||||
|
let mut cellpath: Vec<PathMember> = 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 {})
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
mod binary;
|
mod binary;
|
||||||
mod bool;
|
mod bool;
|
||||||
|
mod cellpath;
|
||||||
mod command;
|
mod command;
|
||||||
mod datetime;
|
mod datetime;
|
||||||
mod decimal;
|
mod decimal;
|
||||||
@ -12,6 +13,7 @@ mod string;
|
|||||||
pub use self::bool::SubCommand as IntoBool;
|
pub use self::bool::SubCommand as IntoBool;
|
||||||
pub use self::filesize::SubCommand as IntoFilesize;
|
pub use self::filesize::SubCommand as IntoFilesize;
|
||||||
pub use binary::SubCommand as IntoBinary;
|
pub use binary::SubCommand as IntoBinary;
|
||||||
|
pub use cellpath::SubCommand as IntoCellPath;
|
||||||
pub use command::Into;
|
pub use command::Into;
|
||||||
pub use datetime::SubCommand as IntoDatetime;
|
pub use datetime::SubCommand as IntoDatetime;
|
||||||
pub use decimal::SubCommand as IntoDecimal;
|
pub use decimal::SubCommand as IntoDecimal;
|
||||||
|
@ -370,6 +370,7 @@ pub fn create_default_context() -> EngineState {
|
|||||||
IntoDuration,
|
IntoDuration,
|
||||||
IntoFilesize,
|
IntoFilesize,
|
||||||
IntoInt,
|
IntoInt,
|
||||||
|
IntoCellPath,
|
||||||
IntoRecord,
|
IntoRecord,
|
||||||
IntoString,
|
IntoString,
|
||||||
};
|
};
|
||||||
|
14
crates/nu-command/tests/commands/into_cellpath.rs
Normal file
14
crates/nu-command/tests/commands/into_cellpath.rs
Normal file
@ -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"));
|
||||||
|
}
|
@ -34,6 +34,7 @@ mod headers;
|
|||||||
mod help;
|
mod help;
|
||||||
mod histogram;
|
mod histogram;
|
||||||
mod insert;
|
mod insert;
|
||||||
|
mod into_cellpath;
|
||||||
mod into_filesize;
|
mod into_filesize;
|
||||||
mod into_int;
|
mod into_int;
|
||||||
mod last;
|
mod last;
|
||||||
|
21
src/tests.rs
21
src/tests.rs
@ -25,6 +25,8 @@ use tempfile::NamedTempFile;
|
|||||||
|
|
||||||
pub type TestResult = Result<(), Box<dyn std::error::Error>>;
|
pub type TestResult = Result<(), Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
|
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 {
|
pub fn run_test_with_env(input: &str, expected: &str, env: &HashMap<&str, &str>) -> TestResult {
|
||||||
let mut file = NamedTempFile::new()?;
|
let mut file = NamedTempFile::new()?;
|
||||||
let name = file.path();
|
let name = file.path();
|
||||||
@ -54,6 +56,25 @@ pub fn run_test(input: &str, expected: &str) -> TestResult {
|
|||||||
run_cmd_and_assert(cmd, expected)
|
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)]
|
#[cfg(test)]
|
||||||
fn run_cmd_and_assert(mut cmd: Command, expected: &str) -> TestResult {
|
fn run_cmd_and_assert(mut cmd: Command, expected: &str) -> TestResult {
|
||||||
let output = cmd.output()?;
|
let output = cmd.output()?;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use crate::tests::{run_test, TestResult};
|
use crate::tests::{run_test, TestResult};
|
||||||
|
|
||||||
|
use super::run_test_with_default_config;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn shorthand_env_1() -> TestResult {
|
fn shorthand_env_1() -> TestResult {
|
||||||
run_test(r#"FOO=BAZ $env.FOO"#, "BAZ")
|
run_test(r#"FOO=BAZ $env.FOO"#, "BAZ")
|
||||||
@ -22,3 +24,11 @@ fn convert_non_string_env_var_to_nothing() -> TestResult {
|
|||||||
"nothing",
|
"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",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user