Refactor path commands (#9687)

This commit is contained in:
Jakub Žádník 2023-07-15 00:04:22 +03:00 committed by GitHub
parent 8c52b7a23a
commit ba766de5d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 254 additions and 338 deletions

View File

@ -11,15 +11,10 @@ use nu_protocol::{
use super::PathSubcommandArguments;
struct Arguments {
columns: Option<Vec<String>>,
replace: Option<Spanned<String>>,
}
impl PathSubcommandArguments for Arguments {
fn get_columns(&self) -> Option<Vec<String>> {
self.columns.clone()
}
}
impl PathSubcommandArguments for Arguments {}
#[derive(Clone)]
pub struct SubCommand;
@ -33,15 +28,11 @@ impl Command for SubCommand {
Signature::build("path basename")
.input_output_types(vec![
(Type::String, Type::String),
// TODO: Why do these commands not use CellPaths in a standard way?
(Type::Table(vec![]), Type::Table(vec![])),
(
Type::List(Box::new(Type::String)),
Type::List(Box::new(Type::String)),
),
])
.named(
"columns",
SyntaxShape::Table(vec![]),
"For a record or table input, convert strings in the given columns to their basename",
Some('c'),
)
.named(
"replace",
SyntaxShape::String,
@ -63,7 +54,6 @@ impl Command for SubCommand {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let args = Arguments {
columns: call.get_flag(engine_state, stack, "columns")?,
replace: call.get_flag(engine_state, stack, "replace")?,
};
@ -86,21 +76,12 @@ impl Command for SubCommand {
result: Some(Value::test_string("test.txt")),
},
Example {
description: "Get basename of a path in a column",
example: "ls .. | path basename -c [ name ]",
result: None,
},
Example {
description: "Get basename of a path in a column",
example: "[[name];[C:\\Users\\Joe]] | path basename -c [ name ]",
result: Some(Value::List {
vals: vec![Value::Record {
cols: vec!["name".to_string()],
vals: vec![Value::test_string("Joe")],
span: Span::test_data(),
}],
span: Span::test_data(),
}),
description: "Get basename of a list of paths",
example: r"[ C:\Users\joe, C:\Users\doe ] | path basename",
result: Some(Value::test_list(vec![
Value::test_string("joe"),
Value::test_string("doe"),
])),
},
Example {
description: "Replace basename of a path",
@ -119,16 +100,12 @@ impl Command for SubCommand {
result: Some(Value::test_string("test.txt")),
},
Example {
description: "Get basename of a path by column",
example: "[[name];[/home/joe]] | path basename -c [ name ]",
result: Some(Value::List {
vals: vec![Value::Record {
cols: vec!["name".to_string()],
vals: vec![Value::test_string("joe")],
span: Span::test_data(),
}],
span: Span::test_data(),
}),
description: "Get basename of a list of paths",
example: "[ /home/joe, /home/doe ] | path basename",
result: Some(Value::test_list(vec![
Value::test_string("joe"),
Value::test_string("doe"),
])),
},
Example {
description: "Replace basename of a path",

View File

@ -11,16 +11,11 @@ use nu_protocol::{
use super::PathSubcommandArguments;
struct Arguments {
columns: Option<Vec<String>>,
replace: Option<Spanned<String>>,
num_levels: Option<i64>,
}
impl PathSubcommandArguments for Arguments {
fn get_columns(&self) -> Option<Vec<String>> {
self.columns.clone()
}
}
impl PathSubcommandArguments for Arguments {}
#[derive(Clone)]
pub struct SubCommand;
@ -32,13 +27,13 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("path dirname")
.input_output_types(vec![(Type::String, Type::String)])
.named(
"columns",
SyntaxShape::Table(vec![]),
"For a record or table input, convert strings at the given columns to their dirname",
Some('c'),
)
.input_output_types(vec![
(Type::String, Type::String),
(
Type::List(Box::new(Type::String)),
Type::List(Box::new(Type::String)),
),
])
.named(
"replace",
SyntaxShape::String,
@ -66,7 +61,6 @@ impl Command for SubCommand {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let args = Arguments {
columns: call.get_flag(engine_state, stack, "columns")?,
replace: call.get_flag(engine_state, stack, "replace")?,
num_levels: call.get_flag(engine_state, stack, "num-levels")?,
};
@ -90,9 +84,12 @@ impl Command for SubCommand {
result: Some(Value::test_string("C:\\Users\\joe\\code")),
},
Example {
description: "Get dirname of a path in a column",
example: "ls ('.' | path expand) | path dirname -c [ name ]",
result: None,
description: "Get dirname of a list of paths",
example: r"[ C:\Users\joe\test.txt, C:\Users\doe\test.txt ] | path dirname",
result: Some(Value::test_list(vec![
Value::test_string(r"C:\Users\joe"),
Value::test_string(r"C:\Users\doe"),
])),
},
Example {
description: "Walk up two levels",
@ -117,9 +114,12 @@ impl Command for SubCommand {
result: Some(Value::test_string("/home/joe/code")),
},
Example {
description: "Get dirname of a path in a column",
example: "ls ('.' | path expand) | path dirname -c [ name ]",
result: None,
description: "Get dirname of a list of paths",
example: "[ /home/joe/test.txt, /home/doe/test.txt ] | path dirname",
result: Some(Value::test_list(vec![
Value::test_string("/home/joe"),
Value::test_string("/home/doe"),
])),
},
Example {
description: "Walk up two levels",

View File

@ -1,25 +1,20 @@
use std::path::{Path, PathBuf};
use nu_engine::{current_dir, CallExt};
use nu_engine::current_dir;
use nu_path::expand_path_with;
use nu_protocol::ast::Call;
use nu_protocol::engine::{EngineState, Stack};
use nu_protocol::{
engine::Command, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
engine::Command, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
use super::PathSubcommandArguments;
struct Arguments {
columns: Option<Vec<String>>,
pwd: PathBuf,
}
impl PathSubcommandArguments for Arguments {
fn get_columns(&self) -> Option<Vec<String>> {
self.columns.clone()
}
}
impl PathSubcommandArguments for Arguments {}
#[derive(Clone)]
pub struct SubCommand;
@ -30,14 +25,13 @@ impl Command for SubCommand {
}
fn signature(&self) -> Signature {
Signature::build("path exists")
.input_output_types(vec![(Type::String, Type::Bool)])
.named(
"columns",
SyntaxShape::Table(vec![]),
"For a record or table input, check strings at the given columns, and replace with result",
Some('c'),
)
Signature::build("path exists").input_output_types(vec![
(Type::String, Type::Bool),
(
Type::List(Box::new(Type::String)),
Type::List(Box::new(Type::Bool)),
),
])
}
fn usage(&self) -> &str {
@ -58,7 +52,6 @@ If you need to distinguish dirs and files, please use `path type`."#
) -> Result<PipelineData, ShellError> {
let head = call.head;
let args = Arguments {
columns: call.get_flag(engine_state, stack, "columns")?,
pwd: current_dir(engine_state, stack)?,
};
// This doesn't match explicit nulls
@ -80,9 +73,12 @@ If you need to distinguish dirs and files, please use `path type`."#
result: Some(Value::test_bool(false)),
},
Example {
description: "Check if a file exists in a column",
example: "ls | path exists -c [ name ]",
result: None,
description: "Check if files in list exist",
example: r"[ C:\joe\todo.txt, C:\Users\doe\todo.txt ] | path exists",
result: Some(Value::test_list(vec![
Value::test_bool(false),
Value::test_bool(false),
])),
},
]
}
@ -96,9 +92,12 @@ If you need to distinguish dirs and files, please use `path type`."#
result: Some(Value::test_bool(false)),
},
Example {
description: "Check if a file exists in a column",
example: "ls | path exists -c [ name ]",
result: None,
description: "Check if files in list exist",
example: "[ /home/joe/todo.txt, /home/doe/todo.txt ] | path exists",
result: Some(Value::test_list(vec![
Value::test_bool(false),
Value::test_bool(false),
])),
},
]
}

View File

@ -1,28 +1,22 @@
use std::path::Path;
use nu_engine::env::current_dir_str;
use nu_engine::CallExt;
use nu_path::{canonicalize_with, expand_path_with};
use nu_protocol::ast::Call;
use nu_protocol::engine::{EngineState, Stack};
use nu_protocol::{
engine::Command, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
engine::Command, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
use super::PathSubcommandArguments;
struct Arguments {
strict: bool,
columns: Option<Vec<String>>,
cwd: String,
not_follow_symlink: bool,
}
impl PathSubcommandArguments for Arguments {
fn get_columns(&self) -> Option<Vec<String>> {
self.columns.clone()
}
}
impl PathSubcommandArguments for Arguments {}
#[derive(Clone)]
pub struct SubCommand;
@ -34,19 +28,19 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("path expand")
.input_output_types(vec![(Type::String, Type::String)])
.input_output_types(vec![
(Type::String, Type::String),
(
Type::List(Box::new(Type::String)),
Type::List(Box::new(Type::String)),
),
])
.switch(
"strict",
"Throw an error if the path could not be expanded",
Some('s'),
)
.switch("no-symlink", "Do not resolve symbolic links", Some('n'))
.named(
"columns",
SyntaxShape::Table(vec![]),
"For a record or table input, expand strings at the given columns",
Some('c'),
)
}
fn usage(&self) -> &str {
@ -63,7 +57,6 @@ impl Command for SubCommand {
let head = call.head;
let args = Arguments {
strict: call.has_flag("strict"),
columns: call.get_flag(engine_state, stack, "columns")?,
cwd: current_dir_str(engine_state, stack)?,
not_follow_symlink: call.has_flag("no-symlink"),
};
@ -85,20 +78,18 @@ impl Command for SubCommand {
example: r"'C:\Users\joe\foo\..\bar' | path expand",
result: Some(Value::test_string(r"C:\Users\joe\bar")),
},
Example {
description: "Expand a path in a column",
example: "ls | path expand -c [ name ]",
result: None,
},
Example {
description: "Expand a relative path",
example: r"'foo\..\bar' | path expand",
result: None,
},
Example {
description: "Expand an absolute path without following symlink",
example: r"'foo\..\bar' | path expand -n",
result: None,
description: "Expand a list of paths",
example: r"[ C:\foo\..\bar, C:\foo\..\baz ] | path expand",
result: Some(Value::test_list(vec![
Value::test_string(r"C:\bar"),
Value::test_string(r"C:\baz"),
])),
},
]
}
@ -111,16 +102,19 @@ impl Command for SubCommand {
example: "'/home/joe/foo/../bar' | path expand",
result: Some(Value::test_string("/home/joe/bar")),
},
Example {
description: "Expand a path in a column",
example: "ls | path expand -c [ name ]",
result: None,
},
Example {
description: "Expand a relative path",
example: "'foo/../bar' | path expand",
result: None,
},
Example {
description: "Expand a list of paths",
example: "[ /foo/../bar, /foo/../baz ] | path expand",
result: Some(Value::test_list(vec![
Value::test_string("/bar"),
Value::test_string("/baz"),
])),
},
]
}
}

View File

@ -12,15 +12,10 @@ use nu_protocol::{
use super::PathSubcommandArguments;
struct Arguments {
columns: Option<Vec<String>>,
append: Vec<Spanned<String>>,
}
impl PathSubcommandArguments for Arguments {
fn get_columns(&self) -> Option<Vec<String>> {
self.columns.clone()
}
}
impl PathSubcommandArguments for Arguments {}
#[derive(Clone)]
pub struct SubCommand;
@ -38,13 +33,6 @@ impl Command for SubCommand {
(Type::Record(vec![]), Type::String),
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
])
.named(
"columns",
SyntaxShape::Table(vec![]),
"For a record or table input, join strings at the given columns",
Some('c'),
)
.allow_variants_without_examples(true)
.rest("append", SyntaxShape::String, "Path to append to the input")
}
@ -66,7 +54,6 @@ the output of 'path parse' and 'path split' subcommands."#
) -> Result<PipelineData, ShellError> {
let head = call.head;
let args = Arguments {
columns: call.get_flag(engine_state, stack, "columns")?,
append: call.rest(engine_state, stack, 0)?,
};
@ -105,11 +92,6 @@ the output of 'path parse' and 'path split' subcommands."#
example: r"'C:\Users\viking' | path join spams this_spam.txt",
result: Some(Value::test_string(r"C:\Users\viking\spams\this_spam.txt")),
},
Example {
description: "Append a filename to a path inside a column",
example: r"ls | path join spam.txt -c [ name ]",
result: None,
},
Example {
description: "Join a list of parts into a path",
example: r"[ 'C:' '\' 'Users' 'viking' 'spam.txt' ] | path join",
@ -117,6 +99,11 @@ the output of 'path parse' and 'path split' subcommands."#
},
Example {
description: "Join a structured path into a path",
example: r"{ parent: 'C:\Users\viking', stem: 'spam', extension: 'txt' } | path join",
result: Some(Value::test_string(r"C:\Users\viking\spam.txt")),
},
Example {
description: "Join a table of structured paths into a list of paths",
example: r"[ [parent stem extension]; ['C:\Users\viking' 'spam' 'txt']] | path join",
result: Some(Value::List {
vals: vec![Value::test_string(r"C:\Users\viking\spam.txt")],
@ -139,11 +126,6 @@ the output of 'path parse' and 'path split' subcommands."#
example: r"'/home/viking' | path join spams this_spam.txt",
result: Some(Value::test_string(r"/home/viking/spams/this_spam.txt")),
},
Example {
description: "Append a filename to a path inside a column",
example: r"ls | path join spam.txt -c [ name ]",
result: None,
},
Example {
description: "Join a list of parts into a path",
example: r"[ '/' 'home' 'viking' 'spam.txt' ] | path join",
@ -151,6 +133,11 @@ the output of 'path parse' and 'path split' subcommands."#
},
Example {
description: "Join a structured path into a path",
example: r"{ parent: '/home/viking', stem: 'spam', extension: 'txt' } | path join",
result: Some(Value::test_string(r"/home/viking/spam.txt")),
},
Example {
description: "Join a table of structured paths into a list of paths",
example: r"[[ parent stem extension ]; [ '/home/viking' 'spam' 'txt' ]] | path join",
result: Some(Value::List {
vals: vec![Value::test_string(r"/home/viking/spam.txt")],
@ -209,24 +196,11 @@ fn join_list(parts: &[Value], head: Span, span: Span, args: &Arguments) -> Value
}
fn join_record(cols: &[String], vals: &[Value], head: Span, span: Span, args: &Arguments) -> Value {
if args.columns.is_some() {
super::operate(
&join_single,
args,
Value::Record {
cols: cols.to_vec(),
vals: vals.to_vec(),
span,
},
span,
)
} else {
match merge_record(cols, vals, head, span) {
Ok(p) => join_single(p.as_path(), head, args),
Err(error) => Value::Error {
error: Box::new(error),
},
}
match merge_record(cols, vals, head, span) {
Ok(p) => join_single(p.as_path(), head, args),
Err(error) => Value::Error {
error: Box::new(error),
},
}
}

View File

@ -29,9 +29,7 @@ const ALLOWED_COLUMNS: [&str; 4] = ["prefix", "parent", "stem", "extension"];
#[cfg(not(windows))]
const ALLOWED_COLUMNS: [&str; 3] = ["parent", "stem", "extension"];
trait PathSubcommandArguments {
fn get_columns(&self) -> Option<Vec<String>>;
}
trait PathSubcommandArguments {}
fn operate<F, A>(cmd: &F, args: &A, v: Value, name: Span) -> Value
where
@ -40,45 +38,6 @@ where
{
match v {
Value::String { val, span } => cmd(StdPath::new(&val), span, args),
Value::Record { cols, vals, span } => {
let col = if let Some(col) = args.get_columns() {
col
} else {
vec![]
};
if col.is_empty() {
return Value::Error {
error: Box::new(ShellError::UnsupportedInput(
String::from("when the input is a table, you must specify the columns"),
"value originates from here".into(),
name,
span,
)),
};
}
let mut output_cols = vec![];
let mut output_vals = vec![];
for (k, v) in cols.iter().zip(vals) {
output_cols.push(k.clone());
if col.contains(k) {
let new_val = match v {
Value::String { val, span } => cmd(StdPath::new(&val), span, args),
_ => return handle_invalid_values(v, name),
};
output_vals.push(new_val);
} else {
output_vals.push(v);
}
}
Value::Record {
cols: output_cols,
vals: output_vals,
span,
}
}
_ => handle_invalid_values(v, name),
}
}

View File

@ -12,15 +12,10 @@ use nu_protocol::{
use super::PathSubcommandArguments;
struct Arguments {
columns: Option<Vec<String>>,
extension: Option<Spanned<String>>,
}
impl PathSubcommandArguments for Arguments {
fn get_columns(&self) -> Option<Vec<String>> {
self.columns.clone()
}
}
impl PathSubcommandArguments for Arguments {}
#[derive(Clone)]
pub struct SubCommand;
@ -32,13 +27,10 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("path parse")
.input_output_types(vec![(Type::String, Type::Record(vec![]))])
.named(
"columns",
SyntaxShape::Table(vec![]),
"For a record or table input, convert strings at the given columns",
Some('c'),
)
.input_output_types(vec![
(Type::String, Type::Record(vec![])),
(Type::List(Box::new(Type::String)), Type::Table(vec![])),
])
.named(
"extension",
SyntaxShape::String,
@ -65,7 +57,6 @@ On Windows, an extra 'prefix' column is added."#
) -> Result<PipelineData, ShellError> {
let head = call.head;
let args = Arguments {
columns: call.get_flag(engine_state, stack, "columns")?,
extension: call.get_flag(engine_state, stack, "extension")?,
};
@ -126,9 +117,40 @@ On Windows, an extra 'prefix' column is added."#
}),
},
Example {
description: "Parse all paths under the 'name' column",
example: r"ls | path parse -c [ name ]",
result: None,
description: "Parse all paths in a list",
example: r"[ C:\Users\viking.d C:\Users\spam.txt ] | path parse",
result: Some(Value::test_list(vec![
Value::Record {
cols: vec![
"prefix".into(),
"parent".into(),
"stem".into(),
"extension".into(),
],
vals: vec![
Value::test_string("C:"),
Value::test_string(r"C:\Users"),
Value::test_string("viking"),
Value::test_string("d"),
],
span: Span::test_data(),
},
Value::Record {
cols: vec![
"prefix".into(),
"parent".into(),
"stem".into(),
"extension".into(),
],
vals: vec![
Value::test_string("C:"),
Value::test_string(r"C:\Users"),
Value::test_string("spam"),
Value::test_string("txt"),
],
span: Span::test_data(),
},
])),
},
]
}
@ -168,9 +190,28 @@ On Windows, an extra 'prefix' column is added."#
}),
},
Example {
description: "Parse all paths under the 'name' column",
example: r"ls | path parse -c [ name ]",
result: None,
description: "Parse all paths in a list",
example: r"[ /home/viking.d /home/spam.txt ] | path parse",
result: Some(Value::test_list(vec![
Value::Record {
cols: vec!["parent".into(), "stem".into(), "extension".into()],
vals: vec![
Value::test_string("/home"),
Value::test_string("viking"),
Value::test_string("d"),
],
span: Span::test_data(),
},
Value::Record {
cols: vec!["parent".into(), "stem".into(), "extension".into()],
vals: vec![
Value::test_string("/home"),
Value::test_string("spam"),
Value::test_string("txt"),
],
span: Span::test_data(),
},
])),
},
]
}

View File

@ -13,14 +13,9 @@ use super::PathSubcommandArguments;
struct Arguments {
path: Spanned<String>,
columns: Option<Vec<String>>,
}
impl PathSubcommandArguments for Arguments {
fn get_columns(&self) -> Option<Vec<String>> {
self.columns.clone()
}
}
impl PathSubcommandArguments for Arguments {}
#[derive(Clone)]
pub struct SubCommand;
@ -32,18 +27,18 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("path relative-to")
.input_output_types(vec![(Type::String, Type::String)])
.input_output_types(vec![
(Type::String, Type::String),
(
Type::List(Box::new(Type::String)),
Type::List(Box::new(Type::String)),
),
])
.required(
"path",
SyntaxShape::String,
"Parent shared with the input path",
)
.named(
"columns",
SyntaxShape::Table(vec![]),
"For a record or table input, convert strings at the given columns",
Some('c'),
)
}
fn usage(&self) -> &str {
@ -66,7 +61,6 @@ path."#
let head = call.head;
let args = Arguments {
path: call.req(engine_state, stack, 0)?,
columns: call.get_flag(engine_state, stack, "columns")?,
};
// This doesn't match explicit nulls
@ -88,9 +82,12 @@ path."#
result: Some(Value::test_string(r"viking")),
},
Example {
description: "Find a relative path from two absolute paths in a column",
example: "ls ~ | path relative-to ~ -c [ name ]",
result: None,
description: "Find a relative path from absolute paths in list",
example: r"[ C:\Users\viking, C:\Users\spam ] | path relative-to C:\Users",
result: Some(Value::test_list(vec![
Value::test_string("viking"),
Value::test_string("spam"),
])),
},
Example {
description: "Find a relative path from two relative paths",
@ -109,9 +106,12 @@ path."#
result: Some(Value::test_string(r"viking")),
},
Example {
description: "Find a relative path from two absolute paths in a column",
example: "ls ~ | path relative-to ~ -c [ name ]",
result: None,
description: "Find a relative path from absolute paths in list",
example: r"[ /home/viking, /home/spam ] | path relative-to '/home'",
result: Some(Value::test_list(vec![
Value::test_string("viking"),
Value::test_string("spam"),
])),
},
Example {
description: "Find a relative path from two relative paths",

View File

@ -1,23 +1,16 @@
use std::path::{Component, Path};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{EngineState, Stack};
use nu_protocol::{
engine::Command, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
engine::Command, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
use super::PathSubcommandArguments;
struct Arguments {
columns: Option<Vec<String>>,
}
struct Arguments;
impl PathSubcommandArguments for Arguments {
fn get_columns(&self) -> Option<Vec<String>> {
self.columns.clone()
}
}
impl PathSubcommandArguments for Arguments {}
#[derive(Clone)]
pub struct SubCommand;
@ -28,14 +21,13 @@ impl Command for SubCommand {
}
fn signature(&self) -> Signature {
Signature::build("path split")
.input_output_types(vec![(Type::String, Type::List(Box::new(Type::String)))])
.named(
"columns",
SyntaxShape::Table(vec![]),
"For a record or table input, split strings at the given columns",
Some('c'),
)
Signature::build("path split").input_output_types(vec![
(Type::String, Type::List(Box::new(Type::String))),
(
Type::List(Box::new(Type::String)),
Type::List(Box::new(Type::List(Box::new(Type::String)))),
),
])
}
fn usage(&self) -> &str {
@ -45,14 +37,12 @@ impl Command for SubCommand {
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let args = Arguments {
columns: call.get_flag(engine_state, stack, "columns")?,
};
let args = Arguments;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
@ -81,9 +71,25 @@ impl Command for SubCommand {
}),
},
Example {
description: "Split all paths under the 'name' column",
example: r"ls ('.' | path expand) | path split -c [ name ]",
result: None,
description: "Split paths in list into parts",
example: r"[ C:\Users\viking\spam.txt C:\Users\viking\eggs.txt ] | path split",
result: Some(Value::List {
vals: vec![
Value::test_list(vec![
Value::test_string(r"C:\"),
Value::test_string("Users"),
Value::test_string("viking"),
Value::test_string("spam.txt"),
]),
Value::test_list(vec![
Value::test_string(r"C:\"),
Value::test_string("Users"),
Value::test_string("viking"),
Value::test_string("eggs.txt"),
]),
],
span: Span::test_data(),
}),
},
]
}
@ -105,9 +111,25 @@ impl Command for SubCommand {
}),
},
Example {
description: "Split all paths under the 'name' column",
example: r"ls ('.' | path expand) | path split -c [ name ]",
result: None,
description: "Split paths in list into parts",
example: r"[ /home/viking/spam.txt /home/viking/eggs.txt ] | path split",
result: Some(Value::List {
vals: vec![
Value::test_list(vec![
Value::test_string("/"),
Value::test_string("home"),
Value::test_string("viking"),
Value::test_string("spam.txt"),
]),
Value::test_list(vec![
Value::test_string("/"),
Value::test_string("home"),
Value::test_string("viking"),
Value::test_string("eggs.txt"),
]),
],
span: Span::test_data(),
}),
},
]
}

View File

@ -1,23 +1,16 @@
use std::path::Path;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{EngineState, Stack};
use nu_protocol::{
engine::Command, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
engine::Command, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
use super::PathSubcommandArguments;
struct Arguments {
columns: Option<Vec<String>>,
}
struct Arguments;
impl PathSubcommandArguments for Arguments {
fn get_columns(&self) -> Option<Vec<String>> {
self.columns.clone()
}
}
impl PathSubcommandArguments for Arguments {}
#[derive(Clone)]
pub struct SubCommand;
@ -29,13 +22,14 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("path type")
.input_output_types(vec![(Type::String, Type::String)])
.named(
"columns",
SyntaxShape::Table(vec![]),
"For a record or table input, check strings at the given columns, and replace with result",
Some('c'),
)
.input_output_types(vec![
(Type::String, Type::String),
(
Type::List(Box::new(Type::String)),
Type::List(Box::new(Type::String)),
),
])
.allow_variants_without_examples(true)
}
fn usage(&self) -> &str {
@ -50,14 +44,12 @@ If nothing is found, an empty string will be returned."#
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let args = Arguments {
columns: call.get_flag(engine_state, stack, "columns")?,
};
let args = Arguments;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
@ -77,8 +69,8 @@ If nothing is found, an empty string will be returned."#
result: Some(Value::test_string("dir")),
},
Example {
description: "Show type of a filepath in a column",
example: "ls | path type -c [ name ]",
description: "Show type of a filepaths in a list",
example: "ls | get name | path type",
result: None,
},
]

View File

@ -2,21 +2,6 @@ use nu_test_support::{nu, pipeline};
use super::join_path_sep;
#[test]
fn returns_path_joined_with_column_path() {
let actual = nu!(
cwd: "tests", pipeline(
r#"
echo [ [name]; [eggs] ]
| path join spam.txt -c [ name ]
| get name.0
"#
));
let expected = join_path_sep(&["eggs", "spam.txt"]);
assert_eq!(actual.out, expected);
}
#[test]
fn returns_path_joined_from_list() {
let actual = nu!(

View File

@ -99,21 +99,6 @@ fn parses_ignoring_extension_gets_stem() {
assert_eq!(actual.out, "spam.tar.gz");
}
#[test]
fn parses_column_path_extension() {
let actual = nu!(
cwd: "tests", pipeline(
r#"
echo [[home, barn]; ['home/viking/spam.txt', 'barn/cow/moo.png']]
| path parse -c [ home barn ]
| get barn
| get extension.0
"#
));
assert_eq!(actual.out, "png");
}
#[test]
fn parses_into_correct_number_of_columns() {
let actual = nu!(

View File

@ -25,24 +25,3 @@ fn splits_correctly_single_path() {
assert_eq!(actual.out, "spam.txt");
}
#[test]
fn splits_correctly_with_column_path() {
let actual = nu!(
cwd: "tests", pipeline(
r#"
echo [
[home, barn];
['home/viking/spam.txt', 'barn/cow/moo.png']
['home/viking/eggs.txt', 'barn/goat/cheese.png']
]
| path split -c [ home barn ]
| get barn
| flatten
| length
"#
));
assert_eq!(actual.out, "6");
}

View File

@ -1740,6 +1740,15 @@ impl Value {
}
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_list(vals: Vec<Value>) -> Value {
Value::List {
vals,
span: Span::test_data(),
}
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_date(val: DateTime<FixedOffset>) -> Value {