diff --git a/crates/nu-command/src/commands/path/basename.rs b/crates/nu-command/src/commands/path/basename.rs index 0ddc8c825a..21a1901b8d 100644 --- a/crates/nu-command/src/commands/path/basename.rs +++ b/crates/nu-command/src/commands/path/basename.rs @@ -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, + columns: Vec, replace: Option>, } impl PathSubcommandArguments for PathBasenameArguments { fn get_column_paths(&self) -> &Vec { - &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 { 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", ))]), diff --git a/crates/nu-command/src/commands/path/dirname.rs b/crates/nu-command/src/commands/path/dirname.rs index 303599aa78..7e000629de 100644 --- a/crates/nu-command/src/commands/path/dirname.rs +++ b/crates/nu-command/src/commands/path/dirname.rs @@ -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, + columns: Vec, replace: Option>, num_levels: Option>, } impl PathSubcommandArguments for PathDirnameArguments { fn get_column_paths(&self) -> &Vec { - &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 { 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", ))]), diff --git a/crates/nu-command/src/commands/path/exists.rs b/crates/nu-command/src/commands/path/exists.rs index de4e9757b8..e88b3b6437 100644 --- a/crates/nu-command/src/commands/path/exists.rs +++ b/crates/nu-command/src/commands/path/exists.rs @@ -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, + columns: Vec, } impl PathSubcommandArguments for PathExistsArguments { fn get_column_paths(&self) -> &Vec { - &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 { 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 { - 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 { - 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, + }, + ] } } diff --git a/crates/nu-command/src/commands/path/expand.rs b/crates/nu-command/src/commands/path/expand.rs index 35431b90cc..e30504e9c7 100644 --- a/crates/nu-command/src/commands/path/expand.rs +++ b/crates/nu-command/src/commands/path/expand.rs @@ -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, + columns: Vec, } impl PathSubcommandArguments for PathExpandArguments { fn get_column_paths(&self) -> &Vec { - &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", diff --git a/crates/nu-command/src/commands/path/join.rs b/crates/nu-command/src/commands/path/join.rs index 3d83f2c963..a81eaf300f 100644 --- a/crates/nu-command/src/commands/path/join.rs +++ b/crates/nu-command/src/commands/path/join.rs @@ -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, + columns: Vec, append: Option>, } impl PathSubcommandArguments for PathJoinArguments { fn get_column_paths(&self) -> &Vec { - &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 { 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", ))]), diff --git a/crates/nu-command/src/commands/path/mod.rs b/crates/nu-command/src/commands/path/mod.rs index ad0cb049ef..ffd2fba52b 100644 --- a/crates/nu-command/src/commands/path/mod.rs +++ b/crates/nu-command/src/commands/path/mod.rs @@ -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, ShellError> { + let column_paths: Option> = 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 = 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) +} diff --git a/crates/nu-command/src/commands/path/parse.rs b/crates/nu-command/src/commands/path/parse.rs index 10b08918a1..81fd30ea44 100644 --- a/crates/nu-command/src/commands/path/parse.rs +++ b/crates/nu-command/src/commands/path/parse.rs @@ -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, + columns: Vec, extension: Option>, } impl PathSubcommandArguments for PathParseArguments { fn get_column_paths(&self) -> &Vec { - &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 { 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, }, ] diff --git a/crates/nu-command/src/commands/path/relative_to.rs b/crates/nu-command/src/commands/path/relative_to.rs index d94d3e5f54..d62b262db2 100644 --- a/crates/nu-command/src/commands/path/relative_to.rs +++ b/crates/nu-command/src/commands/path/relative_to.rs @@ -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, - rest: Vec, + columns: Vec, } impl PathSubcommandArguments for PathRelativeToArguments { fn get_column_paths(&self) -> &Vec { - &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'", diff --git a/crates/nu-command/src/commands/path/split.rs b/crates/nu-command/src/commands/path/split.rs index 2ab7ad9eab..d51505b2da 100644 --- a/crates/nu-command/src/commands/path/split.rs +++ b/crates/nu-command/src/commands/path/split.rs @@ -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, + columns: Vec, } impl PathSubcommandArguments for PathSplitArguments { fn get_column_paths(&self) -> &Vec { - &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 { 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, }, ] diff --git a/crates/nu-command/src/commands/path/type.rs b/crates/nu-command/src/commands/path/type.rs index 5941b6297e..041f9fbf0b 100644 --- a/crates/nu-command/src/commands/path/type.rs +++ b/crates/nu-command/src/commands/path/type.rs @@ -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, + columns: Vec, } impl PathSubcommandArguments for PathTypeArguments { fn get_column_paths(&self) -> &Vec { - &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 { 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 { - 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, + }, + ] } } diff --git a/crates/nu-command/tests/commands/path/join.rs b/crates/nu-command/tests/commands/path/join.rs index cc818706ef..b7ffa73538 100644 --- a/crates/nu-command/tests/commands/path/join.rs +++ b/crates/nu-command/tests/commands/path/join.rs @@ -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 "# )); diff --git a/crates/nu-command/tests/commands/path/parse.rs b/crates/nu-command/tests/commands/path/parse.rs index 42a365d48a..b4ffb3b65e 100644 --- a/crates/nu-command/tests/commands/path/parse.rs +++ b/crates/nu-command/tests/commands/path/parse.rs @@ -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 "# diff --git a/crates/nu-command/tests/commands/path/split.rs b/crates/nu-command/tests/commands/path/split.rs index ba70d442f6..97f1cbd37f 100644 --- a/crates/nu-command/tests/commands/path/split.rs +++ b/crates/nu-command/tests/commands/path/split.rs @@ -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 "# diff --git a/crates/nu-engine/src/from_value.rs b/crates/nu-engine/src/from_value.rs index 84906f19d6..05c627bf3d 100644 --- a/crates/nu-engine/src/from_value.rs +++ b/crates/nu-engine/src/from_value.rs @@ -101,6 +101,7 @@ impl FromValue for i64 { v.as_i64() } } + impl FromValue for Tagged { fn from_value(v: &Value) -> Result { let tag = v.tag.clone();