Path commands: Put column path args behid flag; Allow path join appending without flag (#4008)

* Change path join signature

* Appending now works without flag
* Column path operation is behind a -c flag

* Move column path arg retrieval to a function

Also improves errors

* Fix path join tests

* Propagate column path changes to all path commands

* Update path command examples with columns paths

* Modernize path command examples by removing "echo"

* Improve structured path error message

* Fix typo
This commit is contained in:
Jakub Žádník 2021-09-15 21:03:51 +03:00 committed by GitHub
parent 7fc65067cf
commit cc3653cfd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 238 additions and 122 deletions

View File

@ -1,4 +1,4 @@
use super::{operate, PathSubcommandArguments};
use super::{column_paths_from_args, operate, PathSubcommandArguments};
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
@ -9,13 +9,13 @@ use std::path::Path;
pub struct PathBasename;
struct PathBasenameArguments {
rest: Vec<ColumnPath>,
columns: Vec<ColumnPath>,
replace: Option<Tagged<String>>,
}
impl PathSubcommandArguments for PathBasenameArguments {
fn get_column_paths(&self) -> &Vec<ColumnPath> {
&self.rest
&self.columns
}
}
@ -26,10 +26,11 @@ impl WholeStreamCommand for PathBasename {
fn signature(&self) -> Signature {
Signature::build("path basename")
.rest(
"rest",
SyntaxShape::ColumnPath,
.named(
"columns",
SyntaxShape::Table,
"Optionally operate by column path",
Some('c'),
)
.named(
"replace",
@ -46,7 +47,7 @@ impl WholeStreamCommand for PathBasename {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let cmd_args = Arc::new(PathBasenameArguments {
rest: args.rest(0)?,
columns: column_paths_from_args(&args)?,
replace: args.get_flag("replace")?,
});
@ -58,12 +59,17 @@ impl WholeStreamCommand for PathBasename {
vec![
Example {
description: "Get basename of a path",
example: "echo 'C:\\Users\\joe\\test.txt' | path basename",
example: "'C:\\Users\\joe\\test.txt' | path basename",
result: Some(vec![Value::from("test.txt")]),
},
Example {
description: "Get basename of a path in a column",
example: "ls .. | path basename -c [ name ]",
result: None,
},
Example {
description: "Replace basename of a path",
example: "echo 'C:\\Users\\joe\\test.txt' | path basename -r 'spam.png'",
example: "'C:\\Users\\joe\\test.txt' | path basename -r 'spam.png'",
result: Some(vec![Value::from(UntaggedValue::filepath(
"C:\\Users\\joe\\spam.png",
))]),
@ -76,12 +82,17 @@ impl WholeStreamCommand for PathBasename {
vec![
Example {
description: "Get basename of a path",
example: "echo '/home/joe/test.txt' | path basename",
example: "'/home/joe/test.txt' | path basename",
result: Some(vec![Value::from("test.txt")]),
},
Example {
description: "Get basename of a path in a column",
example: "ls .. | path basename -c [ name ]",
result: None,
},
Example {
description: "Replace basename of a path",
example: "echo '/home/joe/test.txt' | path basename -r 'spam.png'",
example: "'/home/joe/test.txt' | path basename -r 'spam.png'",
result: Some(vec![Value::from(UntaggedValue::filepath(
"/home/joe/spam.png",
))]),

View File

@ -1,4 +1,4 @@
use super::{operate, PathSubcommandArguments};
use super::{column_paths_from_args, operate, PathSubcommandArguments};
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
@ -9,14 +9,14 @@ use std::path::Path;
pub struct PathDirname;
struct PathDirnameArguments {
rest: Vec<ColumnPath>,
columns: Vec<ColumnPath>,
replace: Option<Tagged<String>>,
num_levels: Option<Tagged<u32>>,
}
impl PathSubcommandArguments for PathDirnameArguments {
fn get_column_paths(&self) -> &Vec<ColumnPath> {
&self.rest
&self.columns
}
}
@ -27,10 +27,11 @@ impl WholeStreamCommand for PathDirname {
fn signature(&self) -> Signature {
Signature::build("path dirname")
.rest(
"rest",
SyntaxShape::ColumnPath,
.named(
"columns",
SyntaxShape::Table,
"Optionally operate by column path",
Some('c'),
)
.named(
"replace",
@ -53,7 +54,7 @@ impl WholeStreamCommand for PathDirname {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let cmd_args = Arc::new(PathDirnameArguments {
rest: args.rest(0)?,
columns: column_paths_from_args(&args)?,
replace: args.get_flag("replace")?,
num_levels: args.get_flag("num-levels")?,
});
@ -66,20 +67,25 @@ impl WholeStreamCommand for PathDirname {
vec![
Example {
description: "Get dirname of a path",
example: "echo 'C:\\Users\\joe\\code\\test.txt' | path dirname",
example: "'C:\\Users\\joe\\code\\test.txt' | path dirname",
result: Some(vec![Value::from(UntaggedValue::filepath(
"C:\\Users\\joe\\code",
))]),
},
Example {
description: "Get dirname of a path in a column",
example: "ls ('.' | path expand) | path dirname -c [ name ]",
result: None,
},
Example {
description: "Walk up two levels",
example: "echo 'C:\\Users\\joe\\code\\test.txt' | path dirname -n 2",
example: "'C:\\Users\\joe\\code\\test.txt' | path dirname -n 2",
result: Some(vec![Value::from(UntaggedValue::filepath("C:\\Users\\joe"))]),
},
Example {
description: "Replace the part that would be returned with a custom path",
example:
"echo 'C:\\Users\\joe\\code\\test.txt' | path dirname -n 2 -r C:\\Users\\viking",
"'C:\\Users\\joe\\code\\test.txt' | path dirname -n 2 -r C:\\Users\\viking",
result: Some(vec![Value::from(UntaggedValue::filepath(
"C:\\Users\\viking\\code\\test.txt",
))]),
@ -92,17 +98,22 @@ impl WholeStreamCommand for PathDirname {
vec![
Example {
description: "Get dirname of a path",
example: "echo '/home/joe/code/test.txt' | path dirname",
example: "'/home/joe/code/test.txt' | path dirname",
result: Some(vec![Value::from(UntaggedValue::filepath("/home/joe/code"))]),
},
Example {
description: "Get dirname of a path in a column",
example: "ls ('.' | path expand) | path dirname -c [ name ]",
result: None,
},
Example {
description: "Walk up two levels",
example: "echo '/home/joe/code/test.txt' | path dirname -n 2",
example: "'/home/joe/code/test.txt' | path dirname -n 2",
result: Some(vec![Value::from(UntaggedValue::filepath("/home/joe"))]),
},
Example {
description: "Replace the part that would be returned with a custom path",
example: "echo '/home/joe/code/test.txt' | path dirname -n 2 -r /home/viking",
example: "'/home/joe/code/test.txt' | path dirname -n 2 -r /home/viking",
result: Some(vec![Value::from(UntaggedValue::filepath(
"/home/viking/code/test.txt",
))]),

View File

@ -1,4 +1,4 @@
use super::{operate, PathSubcommandArguments};
use super::{column_paths_from_args, operate, PathSubcommandArguments};
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
@ -8,12 +8,12 @@ use std::path::Path;
pub struct PathExists;
struct PathExistsArguments {
rest: Vec<ColumnPath>,
columns: Vec<ColumnPath>,
}
impl PathSubcommandArguments for PathExistsArguments {
fn get_column_paths(&self) -> &Vec<ColumnPath> {
&self.rest
&self.columns
}
}
@ -23,10 +23,11 @@ impl WholeStreamCommand for PathExists {
}
fn signature(&self) -> Signature {
Signature::build("path exists").rest(
"rest",
SyntaxShape::ColumnPath,
Signature::build("path exists").named(
"columns",
SyntaxShape::Table,
"Optionally operate by column path",
Some('c'),
)
}
@ -37,7 +38,7 @@ impl WholeStreamCommand for PathExists {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let cmd_args = Arc::new(PathExistsArguments {
rest: args.rest(0)?,
columns: column_paths_from_args(&args)?,
});
Ok(operate(args.input, &action, tag.span, cmd_args))
@ -45,20 +46,34 @@ impl WholeStreamCommand for PathExists {
#[cfg(windows)]
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Check if a file exists",
example: "echo 'C:\\Users\\joe\\todo.txt' | path exists",
result: Some(vec![Value::from(UntaggedValue::boolean(false))]),
}]
vec![
Example {
description: "Check if a file exists",
example: "'C:\\Users\\joe\\todo.txt' | path exists",
result: Some(vec![Value::from(UntaggedValue::boolean(false))]),
},
Example {
description: "Check if a file exists in a column",
example: "ls | path exists -c [ name ]",
result: None,
},
]
}
#[cfg(not(windows))]
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Check if a file exists",
example: "echo '/home/joe/todo.txt' | path exists",
result: Some(vec![Value::from(UntaggedValue::boolean(false))]),
}]
vec![
Example {
description: "Check if a file exists",
example: "'/home/joe/todo.txt' | path exists",
result: Some(vec![Value::from(UntaggedValue::boolean(false))]),
},
Example {
description: "Check if a file exists in a column",
example: "ls | path exists -c [ name ]",
result: None,
},
]
}
}

View File

@ -1,4 +1,4 @@
use super::{operate, PathSubcommandArguments};
use super::{column_paths_from_args, operate, PathSubcommandArguments};
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
@ -11,12 +11,12 @@ pub struct PathExpand;
struct PathExpandArguments {
strict: bool,
rest: Vec<ColumnPath>,
columns: Vec<ColumnPath>,
}
impl PathSubcommandArguments for PathExpandArguments {
fn get_column_paths(&self) -> &Vec<ColumnPath> {
&self.rest
&self.columns
}
}
@ -32,10 +32,11 @@ impl WholeStreamCommand for PathExpand {
"Throw an error if the path could not be expanded",
Some('s'),
)
.rest(
"rest",
SyntaxShape::ColumnPath,
.named(
"columns",
SyntaxShape::Table,
"Optionally operate by column path",
Some('c'),
)
}
@ -47,7 +48,7 @@ impl WholeStreamCommand for PathExpand {
let tag = args.call_info.name_tag.clone();
let cmd_args = Arc::new(PathExpandArguments {
strict: args.has_flag("strict"),
rest: args.rest(0)?,
columns: column_paths_from_args(&args)?,
});
Ok(operate(args.input, &action, tag.span, cmd_args))
@ -63,6 +64,11 @@ impl WholeStreamCommand for PathExpand {
UntaggedValue::filepath(r"C:\Users\joe\bar").into_value(Span::new(0, 25))
]),
},
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",
@ -83,6 +89,11 @@ impl WholeStreamCommand for PathExpand {
UntaggedValue::filepath("/home/joe/bar").into_value(Span::new(0, 22))
]),
},
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",

View File

@ -1,4 +1,6 @@
use super::{handle_value, join_path, operate_column_paths, PathSubcommandArguments};
use super::{
column_paths_from_args, handle_value, join_path, operate_column_paths, PathSubcommandArguments,
};
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
@ -9,13 +11,13 @@ use std::path::{Path, PathBuf};
pub struct PathJoin;
struct PathJoinArguments {
rest: Vec<ColumnPath>,
columns: Vec<ColumnPath>,
append: Option<Tagged<PathBuf>>,
}
impl PathSubcommandArguments for PathJoinArguments {
fn get_column_paths(&self) -> &Vec<ColumnPath> {
&self.rest
&self.columns
}
}
@ -26,16 +28,16 @@ impl WholeStreamCommand for PathJoin {
fn signature(&self) -> Signature {
Signature::build("path join")
.rest(
"rest",
SyntaxShape::ColumnPath,
"Optionally operate by column path",
)
.named(
"columns",
SyntaxShape::Table,
"Optionally operate by column path",
Some('c'),
)
.optional(
"append",
SyntaxShape::FilePath,
"Path to append to the input",
Some('a'),
)
}
@ -50,9 +52,10 @@ the output of 'path parse' and 'path split' subcommands."#
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let cmd_args = Arc::new(PathJoinArguments {
rest: args.rest(0)?,
append: args.get_flag("append")?,
columns: column_paths_from_args(&args)?,
append: args.opt(0)?,
});
Ok(operate_join(args.input, &action, tag, cmd_args))
@ -63,21 +66,26 @@ the output of 'path parse' and 'path split' subcommands."#
vec![
Example {
description: "Append a filename to a path",
example: r"echo 'C:\Users\viking' | path join -a spam.txt",
example: r"'C:\Users\viking' | path join spam.txt",
result: Some(vec![Value::from(UntaggedValue::filepath(
r"C:\Users\viking\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"echo [ 'C:' '\' 'Users' 'viking' 'spam.txt' ] | path join",
example: r"[ 'C:' '\' 'Users' 'viking' 'spam.txt' ] | path join",
result: Some(vec![Value::from(UntaggedValue::filepath(
r"C:\Users\viking\spam.txt",
))]),
},
Example {
description: "Join a structured path into a path",
example: r"echo [ [parent stem extension]; ['C:\Users\viking' 'spam' 'txt']] | path join",
example: r"[ [parent stem extension]; ['C:\Users\viking' 'spam' 'txt']] | path join",
result: Some(vec![Value::from(UntaggedValue::filepath(
r"C:\Users\viking\spam.txt",
))]),
@ -90,21 +98,26 @@ the output of 'path parse' and 'path split' subcommands."#
vec![
Example {
description: "Append a filename to a path",
example: r"echo '/home/viking' | path join -a spam.txt",
example: r"'/home/viking' | path join spam.txt",
result: Some(vec![Value::from(UntaggedValue::filepath(
r"/home/viking/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"echo [ '/' 'home' 'viking' 'spam.txt' ] | path join",
example: r"[ '/' 'home' 'viking' 'spam.txt' ] | path join",
result: Some(vec![Value::from(UntaggedValue::filepath(
r"/home/viking/spam.txt",
))]),
},
Example {
description: "Join a structured path into a path",
example: r"echo [[ parent stem extension ]; [ '/home/viking' 'spam' 'txt' ]] | path join",
example: r"[[ parent stem extension ]; [ '/home/viking' 'spam' 'txt' ]] | path join",
result: Some(vec![Value::from(UntaggedValue::filepath(
r"/home/viking/spam.txt",
))]),

View File

@ -61,7 +61,7 @@ fn encode_path(
ALLOWED_COLUMNS.join(", ")
);
return Err(ShellError::labeled_error_with_secondary(
"Invalid column name",
"Expected structured path table",
msg,
new_span,
"originates from here",
@ -216,3 +216,36 @@ where
operate_column_paths(input, action, span, args)
}
}
fn column_paths_from_args(args: &CommandArgs) -> Result<Vec<ColumnPath>, ShellError> {
let column_paths: Option<Vec<Value>> = args.get_flag("columns")?;
let has_columns = column_paths.is_some();
let column_paths = match column_paths {
Some(cols) => {
let mut c = Vec::new();
for col in cols {
let colpath = ColumnPath::build(&col.convert_to_string().spanned_unknown());
if !colpath.is_empty() {
c.push(colpath)
}
}
c
}
None => Vec::new(),
};
if has_columns && column_paths.is_empty() {
let colval: Option<Value> = args.get_flag("columns")?;
let colspan = match colval {
Some(v) => v.tag.span,
None => Span::unknown(),
};
return Err(ShellError::labeled_error(
"Requires a list of columns",
"must be a list of columns",
colspan,
));
}
Ok(column_paths)
}

View File

@ -1,4 +1,4 @@
use super::{operate, PathSubcommandArguments};
use super::{column_paths_from_args, operate, PathSubcommandArguments};
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
@ -11,13 +11,13 @@ use std::path::Path;
pub struct PathParse;
struct PathParseArguments {
rest: Vec<ColumnPath>,
columns: Vec<ColumnPath>,
extension: Option<Tagged<String>>,
}
impl PathSubcommandArguments for PathParseArguments {
fn get_column_paths(&self) -> &Vec<ColumnPath> {
&self.rest
&self.columns
}
}
@ -28,10 +28,11 @@ impl WholeStreamCommand for PathParse {
fn signature(&self) -> Signature {
Signature::build("path parse")
.rest(
"rest",
SyntaxShape::ColumnPath,
.named(
"columns",
SyntaxShape::Table,
"Optionally operate by column path",
Some('c'),
)
.named(
"extension",
@ -53,7 +54,7 @@ On Windows, an extra 'prefix' column is added."#
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let cmd_args = Arc::new(PathParseArguments {
rest: args.rest(0)?,
columns: column_paths_from_args(&args)?,
extension: args.get_flag("extension")?,
});
@ -65,22 +66,22 @@ On Windows, an extra 'prefix' column is added."#
vec![
Example {
description: "Parse a single path",
example: r"echo 'C:\Users\viking\spam.txt' | path parse",
example: r"'C:\Users\viking\spam.txt' | path parse",
result: None,
},
Example {
description: "Replace a complex extension",
example: r"echo 'C:\Users\viking\spam.tar.gz' | path parse -e tar.gz | update extension { 'txt' }",
example: r"'C:\Users\viking\spam.tar.gz' | path parse -e tar.gz | update extension { 'txt' }",
result: None,
},
Example {
description: "Ignore the extension",
example: r"echo 'C:\Users\viking.d' | path parse -e ''",
example: r"'C:\Users\viking.d' | path parse -e ''",
result: None,
},
Example {
description: "Parse all paths under the 'name' column",
example: r"ls | path parse name",
example: r"ls | path parse -c [ name ]",
result: None,
},
]
@ -91,22 +92,22 @@ On Windows, an extra 'prefix' column is added."#
vec![
Example {
description: "Parse a path",
example: r"echo '/home/viking/spam.txt' | path parse",
example: r"'/home/viking/spam.txt' | path parse",
result: None,
},
Example {
description: "Replace a complex extension",
example: r"echo '/home/viking/spam.tar.gz' | path parse -e tar.gz | update extension { 'txt' }",
example: r"'/home/viking/spam.tar.gz' | path parse -e tar.gz | update extension { 'txt' }",
result: None,
},
Example {
description: "Ignore the extension",
example: r"echo '/etc/conf.d' | path parse -e ''",
example: r"'/etc/conf.d' | path parse -e ''",
result: None,
},
Example {
description: "Parse all paths under the 'name' column",
example: r"ls | path parse name",
example: r"ls | path parse -c [ name ]",
result: None,
},
]

View File

@ -1,4 +1,4 @@
use super::{operate, PathSubcommandArguments};
use super::{column_paths_from_args, operate, PathSubcommandArguments};
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
@ -10,12 +10,12 @@ pub struct PathRelativeTo;
struct PathRelativeToArguments {
path: Tagged<PathBuf>,
rest: Vec<ColumnPath>,
columns: Vec<ColumnPath>,
}
impl PathSubcommandArguments for PathRelativeToArguments {
fn get_column_paths(&self) -> &Vec<ColumnPath> {
&self.rest
&self.columns
}
}
@ -31,10 +31,11 @@ impl WholeStreamCommand for PathRelativeTo {
SyntaxShape::FilePath,
"Parent shared with the input path",
)
.rest(
"rest",
SyntaxShape::ColumnPath,
.named(
"columns",
SyntaxShape::Table,
"Optionally operate by column path",
Some('c'),
)
}
@ -52,7 +53,7 @@ path."#
let tag = args.call_info.name_tag.clone();
let cmd_args = Arc::new(PathRelativeToArguments {
path: args.req(0)?,
rest: args.rest(1)?,
columns: column_paths_from_args(&args)?,
});
Ok(operate(args.input, &action, tag.span, cmd_args))
@ -66,6 +67,11 @@ path."#
example: r"'C:\Users\viking' | path relative-to 'C:\Users'",
result: Some(vec![Value::from(UntaggedValue::filepath(r"viking"))]),
},
Example {
description: "Find a relative path from two absolute paths in a column",
example: "ls ~ | path relative-to ~ -c [ name ]",
result: None,
},
Example {
description: "Find a relative path from two relative paths",
example: r"'eggs\bacon\sausage\spam' | path relative-to 'eggs\bacon\sausage'",
@ -82,6 +88,11 @@ path."#
example: r"'/home/viking' | path relative-to '/home'",
result: Some(vec![Value::from(UntaggedValue::filepath(r"viking"))]),
},
Example {
description: "Find a relative path from two absolute paths in a column",
example: "ls ~ | path relative-to ~ -c [ name ]",
result: None,
},
Example {
description: "Find a relative path from two relative paths",
example: r"'eggs/bacon/sausage/spam' | path relative-to 'eggs/bacon/sausage'",

View File

@ -1,4 +1,4 @@
use super::{handle_value, operate_column_paths, PathSubcommandArguments};
use super::{column_paths_from_args, handle_value, operate_column_paths, PathSubcommandArguments};
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
@ -8,12 +8,12 @@ use std::path::Path;
pub struct PathSplit;
struct PathSplitArguments {
rest: Vec<ColumnPath>,
columns: Vec<ColumnPath>,
}
impl PathSubcommandArguments for PathSplitArguments {
fn get_column_paths(&self) -> &Vec<ColumnPath> {
&self.rest
&self.columns
}
}
@ -23,10 +23,11 @@ impl WholeStreamCommand for PathSplit {
}
fn signature(&self) -> Signature {
Signature::build("path split").rest(
"rest",
SyntaxShape::ColumnPath,
Signature::build("path split").named(
"columns",
SyntaxShape::Table,
"Optionally operate by column path",
Some('c'),
)
}
@ -37,7 +38,7 @@ impl WholeStreamCommand for PathSplit {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let cmd_args = Arc::new(PathSplitArguments {
rest: args.rest(0)?,
columns: column_paths_from_args(&args)?,
});
Ok(operate_split(args.input, &action, tag.span, cmd_args))
@ -48,7 +49,7 @@ impl WholeStreamCommand for PathSplit {
vec![
Example {
description: "Split a path into parts",
example: r"echo 'C:\Users\viking\spam.txt' | path split",
example: r"'C:\Users\viking\spam.txt' | path split",
result: Some(vec![
Value::from(UntaggedValue::string("C:")),
Value::from(UntaggedValue::string(r"\")),
@ -59,7 +60,7 @@ impl WholeStreamCommand for PathSplit {
},
Example {
description: "Split all paths under the 'name' column",
example: r"ls | path split name",
example: r"ls ('.' | path expand) | path split -c [ name ]",
result: None,
},
]
@ -70,7 +71,7 @@ impl WholeStreamCommand for PathSplit {
vec![
Example {
description: "Split a path into parts",
example: r"echo '/home/viking/spam.txt' | path split",
example: r"'/home/viking/spam.txt' | path split",
result: Some(vec![
Value::from(UntaggedValue::string("/")),
Value::from(UntaggedValue::string("home")),
@ -80,7 +81,7 @@ impl WholeStreamCommand for PathSplit {
},
Example {
description: "Split all paths under the 'name' column",
example: r"ls | path split name",
example: r"ls ('.' | path expand) | path split -c [ name ]",
result: None,
},
]

View File

@ -1,4 +1,4 @@
use super::{operate, PathSubcommandArguments};
use super::{column_paths_from_args, operate, PathSubcommandArguments};
use crate::prelude::*;
use nu_engine::filesystem::filesystem_shell::get_file_type;
use nu_engine::WholeStreamCommand;
@ -9,12 +9,12 @@ use std::path::Path;
pub struct PathType;
struct PathTypeArguments {
rest: Vec<ColumnPath>,
columns: Vec<ColumnPath>,
}
impl PathSubcommandArguments for PathTypeArguments {
fn get_column_paths(&self) -> &Vec<ColumnPath> {
&self.rest
&self.columns
}
}
@ -24,10 +24,11 @@ impl WholeStreamCommand for PathType {
}
fn signature(&self) -> Signature {
Signature::build("path type").rest(
"rest",
SyntaxShape::ColumnPath,
Signature::build("path type").named(
"columns",
SyntaxShape::Table,
"Optionally operate by column path",
Some('c'),
)
}
@ -38,18 +39,25 @@ impl WholeStreamCommand for PathType {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let cmd_args = Arc::new(PathTypeArguments {
rest: args.rest(0)?,
columns: column_paths_from_args(&args)?,
});
Ok(operate(args.input, &action, tag.span, cmd_args))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Show type of a filepath",
example: "echo '.' | path type",
result: Some(vec![Value::from("Dir")]),
}]
vec![
Example {
description: "Show type of a filepath",
example: "'.' | path type",
result: Some(vec![Value::from("Dir")]),
},
Example {
description: "Show type of a filepath in a column",
example: "ls | path type -c [ name ]",
result: None,
},
]
}
}

View File

@ -8,7 +8,7 @@ fn returns_path_joined_with_column_path() {
cwd: "tests", pipeline(
r#"
echo [ [name]; [eggs] ]
| path join -a spam.txt name
| path join spam.txt -c [ name ]
| get name
"#
));
@ -23,7 +23,7 @@ fn returns_path_joined_from_list() {
cwd: "tests", pipeline(
r#"
echo [ home viking spam.txt ]
| path join
| path join
"#
));
@ -37,7 +37,7 @@ fn appends_slash_when_joined_with_empty_path() {
cwd: "tests", pipeline(
r#"
echo "/some/dir"
| path join -a ''
| path join ''
"#
));
@ -51,7 +51,7 @@ fn returns_joined_path_when_joining_empty_path() {
cwd: "tests", pipeline(
r#"
echo ""
| path join -a foo.txt
| path join foo.txt
"#
));

View File

@ -48,7 +48,7 @@ fn parses_custom_extension_gets_extension() {
let actual = nu!(
cwd: "tests", pipeline(
r#"
echo 'home/viking/spam.tar.gz'
echo 'home/viking/spam.tar.gz'
| path parse -e tar.gz
| get extension
"#
@ -62,7 +62,7 @@ fn parses_custom_extension_gets_stem() {
let actual = nu!(
cwd: "tests", pipeline(
r#"
echo 'home/viking/spam.tar.gz'
echo 'home/viking/spam.tar.gz'
| path parse -e tar.gz
| get stem
"#
@ -76,7 +76,7 @@ fn parses_ignoring_extension_gets_extension() {
let actual = nu!(
cwd: "tests", pipeline(
r#"
echo 'home/viking/spam.tar.gz'
echo 'home/viking/spam.tar.gz'
| path parse -e ''
| get extension
"#
@ -90,7 +90,7 @@ fn parses_ignoring_extension_gets_stem() {
let actual = nu!(
cwd: "tests", pipeline(
r#"
echo 'home/viking/spam.tar.gz'
echo 'home/viking/spam.tar.gz'
| path parse -e ""
| get stem
"#
@ -105,7 +105,7 @@ fn parses_column_path_extension() {
cwd: "tests", pipeline(
r#"
echo [[home, barn]; ['home/viking/spam.txt', 'barn/cow/moo.png']]
| path parse home barn
| path parse -c [ home barn ]
| get barn
| get extension
"#

View File

@ -18,7 +18,7 @@ fn splits_correctly_single_path() {
cwd: "tests", pipeline(
r#"
echo ['home/viking/spam.txt']
| path split
| path split
| last
"#
));
@ -37,7 +37,7 @@ fn splits_correctly_with_column_path() {
['home/viking/spam.txt', 'barn/cow/moo.png']
['home/viking/eggs.txt', 'barn/goat/cheese.png']
]
| path split home barn
| path split -c [ home barn ]
| get barn
| length
"#

View File

@ -101,6 +101,7 @@ impl FromValue for i64 {
v.as_i64()
}
}
impl FromValue for Tagged<i64> {
fn from_value(v: &Value) -> Result<Self, ShellError> {
let tag = v.tag.clone();