mirror of
https://github.com/nushell/nushell
synced 2025-01-14 06:04:09 +00:00
Refactor path commands (#9687)
This commit is contained in:
parent
8c52b7a23a
commit
ba766de5d1
14 changed files with 254 additions and 338 deletions
|
@ -11,15 +11,10 @@ use nu_protocol::{
|
||||||
use super::PathSubcommandArguments;
|
use super::PathSubcommandArguments;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
columns: Option<Vec<String>>,
|
|
||||||
replace: Option<Spanned<String>>,
|
replace: Option<Spanned<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathSubcommandArguments for Arguments {
|
impl PathSubcommandArguments for Arguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>> {
|
|
||||||
self.columns.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -33,15 +28,11 @@ impl Command for SubCommand {
|
||||||
Signature::build("path basename")
|
Signature::build("path basename")
|
||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::String, Type::String),
|
(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(
|
.named(
|
||||||
"replace",
|
"replace",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
|
@ -63,7 +54,6 @@ impl Command for SubCommand {
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let args = Arguments {
|
let args = Arguments {
|
||||||
columns: call.get_flag(engine_state, stack, "columns")?,
|
|
||||||
replace: call.get_flag(engine_state, stack, "replace")?,
|
replace: call.get_flag(engine_state, stack, "replace")?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,21 +76,12 @@ impl Command for SubCommand {
|
||||||
result: Some(Value::test_string("test.txt")),
|
result: Some(Value::test_string("test.txt")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Get basename of a path in a column",
|
description: "Get basename of a list of paths",
|
||||||
example: "ls .. | path basename -c [ name ]",
|
example: r"[ C:\Users\joe, C:\Users\doe ] | path basename",
|
||||||
result: None,
|
result: Some(Value::test_list(vec![
|
||||||
},
|
Value::test_string("joe"),
|
||||||
Example {
|
Value::test_string("doe"),
|
||||||
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(),
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Replace basename of a path",
|
description: "Replace basename of a path",
|
||||||
|
@ -119,16 +100,12 @@ impl Command for SubCommand {
|
||||||
result: Some(Value::test_string("test.txt")),
|
result: Some(Value::test_string("test.txt")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Get basename of a path by column",
|
description: "Get basename of a list of paths",
|
||||||
example: "[[name];[/home/joe]] | path basename -c [ name ]",
|
example: "[ /home/joe, /home/doe ] | path basename",
|
||||||
result: Some(Value::List {
|
result: Some(Value::test_list(vec![
|
||||||
vals: vec![Value::Record {
|
Value::test_string("joe"),
|
||||||
cols: vec!["name".to_string()],
|
Value::test_string("doe"),
|
||||||
vals: vec![Value::test_string("joe")],
|
])),
|
||||||
span: Span::test_data(),
|
|
||||||
}],
|
|
||||||
span: Span::test_data(),
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Replace basename of a path",
|
description: "Replace basename of a path",
|
||||||
|
|
|
@ -11,16 +11,11 @@ use nu_protocol::{
|
||||||
use super::PathSubcommandArguments;
|
use super::PathSubcommandArguments;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
columns: Option<Vec<String>>,
|
|
||||||
replace: Option<Spanned<String>>,
|
replace: Option<Spanned<String>>,
|
||||||
num_levels: Option<i64>,
|
num_levels: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathSubcommandArguments for Arguments {
|
impl PathSubcommandArguments for Arguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>> {
|
|
||||||
self.columns.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -32,13 +27,13 @@ impl Command for SubCommand {
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("path dirname")
|
Signature::build("path dirname")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
.named(
|
(Type::String, Type::String),
|
||||||
"columns",
|
(
|
||||||
SyntaxShape::Table(vec![]),
|
Type::List(Box::new(Type::String)),
|
||||||
"For a record or table input, convert strings at the given columns to their dirname",
|
Type::List(Box::new(Type::String)),
|
||||||
Some('c'),
|
),
|
||||||
)
|
])
|
||||||
.named(
|
.named(
|
||||||
"replace",
|
"replace",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
|
@ -66,7 +61,6 @@ impl Command for SubCommand {
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let args = Arguments {
|
let args = Arguments {
|
||||||
columns: call.get_flag(engine_state, stack, "columns")?,
|
|
||||||
replace: call.get_flag(engine_state, stack, "replace")?,
|
replace: call.get_flag(engine_state, stack, "replace")?,
|
||||||
num_levels: call.get_flag(engine_state, stack, "num-levels")?,
|
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")),
|
result: Some(Value::test_string("C:\\Users\\joe\\code")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Get dirname of a path in a column",
|
description: "Get dirname of a list of paths",
|
||||||
example: "ls ('.' | path expand) | path dirname -c [ name ]",
|
example: r"[ C:\Users\joe\test.txt, C:\Users\doe\test.txt ] | path dirname",
|
||||||
result: None,
|
result: Some(Value::test_list(vec![
|
||||||
|
Value::test_string(r"C:\Users\joe"),
|
||||||
|
Value::test_string(r"C:\Users\doe"),
|
||||||
|
])),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Walk up two levels",
|
description: "Walk up two levels",
|
||||||
|
@ -117,9 +114,12 @@ impl Command for SubCommand {
|
||||||
result: Some(Value::test_string("/home/joe/code")),
|
result: Some(Value::test_string("/home/joe/code")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Get dirname of a path in a column",
|
description: "Get dirname of a list of paths",
|
||||||
example: "ls ('.' | path expand) | path dirname -c [ name ]",
|
example: "[ /home/joe/test.txt, /home/doe/test.txt ] | path dirname",
|
||||||
result: None,
|
result: Some(Value::test_list(vec![
|
||||||
|
Value::test_string("/home/joe"),
|
||||||
|
Value::test_string("/home/doe"),
|
||||||
|
])),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Walk up two levels",
|
description: "Walk up two levels",
|
||||||
|
|
|
@ -1,25 +1,20 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use nu_engine::{current_dir, CallExt};
|
use nu_engine::current_dir;
|
||||||
use nu_path::expand_path_with;
|
use nu_path::expand_path_with;
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{EngineState, Stack};
|
use nu_protocol::engine::{EngineState, Stack};
|
||||||
use nu_protocol::{
|
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;
|
use super::PathSubcommandArguments;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
columns: Option<Vec<String>>,
|
|
||||||
pwd: PathBuf,
|
pwd: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathSubcommandArguments for Arguments {
|
impl PathSubcommandArguments for Arguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>> {
|
|
||||||
self.columns.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -30,14 +25,13 @@ impl Command for SubCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("path exists")
|
Signature::build("path exists").input_output_types(vec![
|
||||||
.input_output_types(vec![(Type::String, Type::Bool)])
|
(Type::String, Type::Bool),
|
||||||
.named(
|
(
|
||||||
"columns",
|
Type::List(Box::new(Type::String)),
|
||||||
SyntaxShape::Table(vec![]),
|
Type::List(Box::new(Type::Bool)),
|
||||||
"For a record or table input, check strings at the given columns, and replace with result",
|
),
|
||||||
Some('c'),
|
])
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
|
@ -58,7 +52,6 @@ If you need to distinguish dirs and files, please use `path type`."#
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let args = Arguments {
|
let args = Arguments {
|
||||||
columns: call.get_flag(engine_state, stack, "columns")?,
|
|
||||||
pwd: current_dir(engine_state, stack)?,
|
pwd: current_dir(engine_state, stack)?,
|
||||||
};
|
};
|
||||||
// This doesn't match explicit nulls
|
// 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)),
|
result: Some(Value::test_bool(false)),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Check if a file exists in a column",
|
description: "Check if files in list exist",
|
||||||
example: "ls | path exists -c [ name ]",
|
example: r"[ C:\joe\todo.txt, C:\Users\doe\todo.txt ] | path exists",
|
||||||
result: None,
|
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)),
|
result: Some(Value::test_bool(false)),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Check if a file exists in a column",
|
description: "Check if files in list exist",
|
||||||
example: "ls | path exists -c [ name ]",
|
example: "[ /home/joe/todo.txt, /home/doe/todo.txt ] | path exists",
|
||||||
result: None,
|
result: Some(Value::test_list(vec![
|
||||||
|
Value::test_bool(false),
|
||||||
|
Value::test_bool(false),
|
||||||
|
])),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,22 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use nu_engine::env::current_dir_str;
|
use nu_engine::env::current_dir_str;
|
||||||
use nu_engine::CallExt;
|
|
||||||
use nu_path::{canonicalize_with, expand_path_with};
|
use nu_path::{canonicalize_with, expand_path_with};
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{EngineState, Stack};
|
use nu_protocol::engine::{EngineState, Stack};
|
||||||
use nu_protocol::{
|
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;
|
use super::PathSubcommandArguments;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
strict: bool,
|
strict: bool,
|
||||||
columns: Option<Vec<String>>,
|
|
||||||
cwd: String,
|
cwd: String,
|
||||||
not_follow_symlink: bool,
|
not_follow_symlink: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathSubcommandArguments for Arguments {
|
impl PathSubcommandArguments for Arguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>> {
|
|
||||||
self.columns.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -34,19 +28,19 @@ impl Command for SubCommand {
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("path expand")
|
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(
|
.switch(
|
||||||
"strict",
|
"strict",
|
||||||
"Throw an error if the path could not be expanded",
|
"Throw an error if the path could not be expanded",
|
||||||
Some('s'),
|
Some('s'),
|
||||||
)
|
)
|
||||||
.switch("no-symlink", "Do not resolve symbolic links", Some('n'))
|
.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 {
|
fn usage(&self) -> &str {
|
||||||
|
@ -63,7 +57,6 @@ impl Command for SubCommand {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let args = Arguments {
|
let args = Arguments {
|
||||||
strict: call.has_flag("strict"),
|
strict: call.has_flag("strict"),
|
||||||
columns: call.get_flag(engine_state, stack, "columns")?,
|
|
||||||
cwd: current_dir_str(engine_state, stack)?,
|
cwd: current_dir_str(engine_state, stack)?,
|
||||||
not_follow_symlink: call.has_flag("no-symlink"),
|
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",
|
example: r"'C:\Users\joe\foo\..\bar' | path expand",
|
||||||
result: Some(Value::test_string(r"C:\Users\joe\bar")),
|
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 {
|
Example {
|
||||||
description: "Expand a relative path",
|
description: "Expand a relative path",
|
||||||
example: r"'foo\..\bar' | path expand",
|
example: r"'foo\..\bar' | path expand",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Expand an absolute path without following symlink",
|
description: "Expand a list of paths",
|
||||||
example: r"'foo\..\bar' | path expand -n",
|
example: r"[ C:\foo\..\bar, C:\foo\..\baz ] | path expand",
|
||||||
result: None,
|
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",
|
example: "'/home/joe/foo/../bar' | path expand",
|
||||||
result: Some(Value::test_string("/home/joe/bar")),
|
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 {
|
Example {
|
||||||
description: "Expand a relative path",
|
description: "Expand a relative path",
|
||||||
example: "'foo/../bar' | path expand",
|
example: "'foo/../bar' | path expand",
|
||||||
result: None,
|
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"),
|
||||||
|
])),
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,15 +12,10 @@ use nu_protocol::{
|
||||||
use super::PathSubcommandArguments;
|
use super::PathSubcommandArguments;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
columns: Option<Vec<String>>,
|
|
||||||
append: Vec<Spanned<String>>,
|
append: Vec<Spanned<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathSubcommandArguments for Arguments {
|
impl PathSubcommandArguments for Arguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>> {
|
|
||||||
self.columns.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -38,13 +33,6 @@ impl Command for SubCommand {
|
||||||
(Type::Record(vec![]), Type::String),
|
(Type::Record(vec![]), Type::String),
|
||||||
(Type::Table(vec![]), Type::List(Box::new(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")
|
.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> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let args = Arguments {
|
let args = Arguments {
|
||||||
columns: call.get_flag(engine_state, stack, "columns")?,
|
|
||||||
append: call.rest(engine_state, stack, 0)?,
|
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",
|
example: r"'C:\Users\viking' | path join spams this_spam.txt",
|
||||||
result: Some(Value::test_string(r"C:\Users\viking\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 {
|
Example {
|
||||||
description: "Join a list of parts into a path",
|
description: "Join a list of parts into a path",
|
||||||
example: r"[ 'C:' '\' 'Users' 'viking' 'spam.txt' ] | path join",
|
example: r"[ 'C:' '\' 'Users' 'viking' 'spam.txt' ] | path join",
|
||||||
|
@ -117,6 +99,11 @@ the output of 'path parse' and 'path split' subcommands."#
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Join a structured path into a path",
|
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",
|
example: r"[ [parent stem extension]; ['C:\Users\viking' 'spam' 'txt']] | path join",
|
||||||
result: Some(Value::List {
|
result: Some(Value::List {
|
||||||
vals: vec![Value::test_string(r"C:\Users\viking\spam.txt")],
|
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",
|
example: r"'/home/viking' | path join spams this_spam.txt",
|
||||||
result: Some(Value::test_string(r"/home/viking/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 {
|
Example {
|
||||||
description: "Join a list of parts into a path",
|
description: "Join a list of parts into a path",
|
||||||
example: r"[ '/' 'home' 'viking' 'spam.txt' ] | path join",
|
example: r"[ '/' 'home' 'viking' 'spam.txt' ] | path join",
|
||||||
|
@ -151,6 +133,11 @@ the output of 'path parse' and 'path split' subcommands."#
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Join a structured path into a path",
|
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",
|
example: r"[[ parent stem extension ]; [ '/home/viking' 'spam' 'txt' ]] | path join",
|
||||||
result: Some(Value::List {
|
result: Some(Value::List {
|
||||||
vals: vec![Value::test_string(r"/home/viking/spam.txt")],
|
vals: vec![Value::test_string(r"/home/viking/spam.txt")],
|
||||||
|
@ -209,25 +196,12 @@ 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 {
|
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) {
|
match merge_record(cols, vals, head, span) {
|
||||||
Ok(p) => join_single(p.as_path(), head, args),
|
Ok(p) => join_single(p.as_path(), head, args),
|
||||||
Err(error) => Value::Error {
|
Err(error) => Value::Error {
|
||||||
error: Box::new(error),
|
error: Box::new(error),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_record(
|
fn merge_record(
|
||||||
|
|
|
@ -29,9 +29,7 @@ const ALLOWED_COLUMNS: [&str; 4] = ["prefix", "parent", "stem", "extension"];
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
const ALLOWED_COLUMNS: [&str; 3] = ["parent", "stem", "extension"];
|
const ALLOWED_COLUMNS: [&str; 3] = ["parent", "stem", "extension"];
|
||||||
|
|
||||||
trait PathSubcommandArguments {
|
trait PathSubcommandArguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn operate<F, A>(cmd: &F, args: &A, v: Value, name: Span) -> Value
|
fn operate<F, A>(cmd: &F, args: &A, v: Value, name: Span) -> Value
|
||||||
where
|
where
|
||||||
|
@ -40,45 +38,6 @@ where
|
||||||
{
|
{
|
||||||
match v {
|
match v {
|
||||||
Value::String { val, span } => cmd(StdPath::new(&val), span, args),
|
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),
|
_ => handle_invalid_values(v, name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,15 +12,10 @@ use nu_protocol::{
|
||||||
use super::PathSubcommandArguments;
|
use super::PathSubcommandArguments;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
columns: Option<Vec<String>>,
|
|
||||||
extension: Option<Spanned<String>>,
|
extension: Option<Spanned<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathSubcommandArguments for Arguments {
|
impl PathSubcommandArguments for Arguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>> {
|
|
||||||
self.columns.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -32,13 +27,10 @@ impl Command for SubCommand {
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("path parse")
|
Signature::build("path parse")
|
||||||
.input_output_types(vec![(Type::String, Type::Record(vec![]))])
|
.input_output_types(vec![
|
||||||
.named(
|
(Type::String, Type::Record(vec![])),
|
||||||
"columns",
|
(Type::List(Box::new(Type::String)), Type::Table(vec![])),
|
||||||
SyntaxShape::Table(vec![]),
|
])
|
||||||
"For a record or table input, convert strings at the given columns",
|
|
||||||
Some('c'),
|
|
||||||
)
|
|
||||||
.named(
|
.named(
|
||||||
"extension",
|
"extension",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
|
@ -65,7 +57,6 @@ On Windows, an extra 'prefix' column is added."#
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let args = Arguments {
|
let args = Arguments {
|
||||||
columns: call.get_flag(engine_state, stack, "columns")?,
|
|
||||||
extension: call.get_flag(engine_state, stack, "extension")?,
|
extension: call.get_flag(engine_state, stack, "extension")?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -126,9 +117,40 @@ On Windows, an extra 'prefix' column is added."#
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Parse all paths under the 'name' column",
|
description: "Parse all paths in a list",
|
||||||
example: r"ls | path parse -c [ name ]",
|
example: r"[ C:\Users\viking.d C:\Users\spam.txt ] | path parse",
|
||||||
result: None,
|
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 {
|
Example {
|
||||||
description: "Parse all paths under the 'name' column",
|
description: "Parse all paths in a list",
|
||||||
example: r"ls | path parse -c [ name ]",
|
example: r"[ /home/viking.d /home/spam.txt ] | path parse",
|
||||||
result: None,
|
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(),
|
||||||
|
},
|
||||||
|
])),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,14 +13,9 @@ use super::PathSubcommandArguments;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
path: Spanned<String>,
|
path: Spanned<String>,
|
||||||
columns: Option<Vec<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathSubcommandArguments for Arguments {
|
impl PathSubcommandArguments for Arguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>> {
|
|
||||||
self.columns.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -32,18 +27,18 @@ impl Command for SubCommand {
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("path relative-to")
|
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(
|
.required(
|
||||||
"path",
|
"path",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
"Parent shared with the input path",
|
"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 {
|
fn usage(&self) -> &str {
|
||||||
|
@ -66,7 +61,6 @@ path."#
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let args = Arguments {
|
let args = Arguments {
|
||||||
path: call.req(engine_state, stack, 0)?,
|
path: call.req(engine_state, stack, 0)?,
|
||||||
columns: call.get_flag(engine_state, stack, "columns")?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// This doesn't match explicit nulls
|
// This doesn't match explicit nulls
|
||||||
|
@ -88,9 +82,12 @@ path."#
|
||||||
result: Some(Value::test_string(r"viking")),
|
result: Some(Value::test_string(r"viking")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Find a relative path from two absolute paths in a column",
|
description: "Find a relative path from absolute paths in list",
|
||||||
example: "ls ~ | path relative-to ~ -c [ name ]",
|
example: r"[ C:\Users\viking, C:\Users\spam ] | path relative-to C:\Users",
|
||||||
result: None,
|
result: Some(Value::test_list(vec![
|
||||||
|
Value::test_string("viking"),
|
||||||
|
Value::test_string("spam"),
|
||||||
|
])),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Find a relative path from two relative paths",
|
description: "Find a relative path from two relative paths",
|
||||||
|
@ -109,9 +106,12 @@ path."#
|
||||||
result: Some(Value::test_string(r"viking")),
|
result: Some(Value::test_string(r"viking")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Find a relative path from two absolute paths in a column",
|
description: "Find a relative path from absolute paths in list",
|
||||||
example: "ls ~ | path relative-to ~ -c [ name ]",
|
example: r"[ /home/viking, /home/spam ] | path relative-to '/home'",
|
||||||
result: None,
|
result: Some(Value::test_list(vec![
|
||||||
|
Value::test_string("viking"),
|
||||||
|
Value::test_string("spam"),
|
||||||
|
])),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Find a relative path from two relative paths",
|
description: "Find a relative path from two relative paths",
|
||||||
|
|
|
@ -1,23 +1,16 @@
|
||||||
use std::path::{Component, Path};
|
use std::path::{Component, Path};
|
||||||
|
|
||||||
use nu_engine::CallExt;
|
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{EngineState, Stack};
|
use nu_protocol::engine::{EngineState, Stack};
|
||||||
use nu_protocol::{
|
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;
|
use super::PathSubcommandArguments;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments;
|
||||||
columns: Option<Vec<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PathSubcommandArguments for Arguments {
|
impl PathSubcommandArguments for Arguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>> {
|
|
||||||
self.columns.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -28,14 +21,13 @@ impl Command for SubCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("path split")
|
Signature::build("path split").input_output_types(vec![
|
||||||
.input_output_types(vec![(Type::String, Type::List(Box::new(Type::String)))])
|
(Type::String, Type::List(Box::new(Type::String))),
|
||||||
.named(
|
(
|
||||||
"columns",
|
Type::List(Box::new(Type::String)),
|
||||||
SyntaxShape::Table(vec![]),
|
Type::List(Box::new(Type::List(Box::new(Type::String)))),
|
||||||
"For a record or table input, split strings at the given columns",
|
),
|
||||||
Some('c'),
|
])
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
|
@ -45,14 +37,12 @@ impl Command for SubCommand {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let args = Arguments {
|
let args = Arguments;
|
||||||
columns: call.get_flag(engine_state, stack, "columns")?,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This doesn't match explicit nulls
|
// This doesn't match explicit nulls
|
||||||
if matches!(input, PipelineData::Empty) {
|
if matches!(input, PipelineData::Empty) {
|
||||||
|
@ -81,9 +71,25 @@ impl Command for SubCommand {
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Split all paths under the 'name' column",
|
description: "Split paths in list into parts",
|
||||||
example: r"ls ('.' | path expand) | path split -c [ name ]",
|
example: r"[ C:\Users\viking\spam.txt C:\Users\viking\eggs.txt ] | path split",
|
||||||
result: None,
|
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 {
|
Example {
|
||||||
description: "Split all paths under the 'name' column",
|
description: "Split paths in list into parts",
|
||||||
example: r"ls ('.' | path expand) | path split -c [ name ]",
|
example: r"[ /home/viking/spam.txt /home/viking/eggs.txt ] | path split",
|
||||||
result: None,
|
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(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,16 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use nu_engine::CallExt;
|
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{EngineState, Stack};
|
use nu_protocol::engine::{EngineState, Stack};
|
||||||
use nu_protocol::{
|
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;
|
use super::PathSubcommandArguments;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments;
|
||||||
columns: Option<Vec<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PathSubcommandArguments for Arguments {
|
impl PathSubcommandArguments for Arguments {}
|
||||||
fn get_columns(&self) -> Option<Vec<String>> {
|
|
||||||
self.columns.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -29,13 +22,14 @@ impl Command for SubCommand {
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("path type")
|
Signature::build("path type")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
.named(
|
(Type::String, Type::String),
|
||||||
"columns",
|
(
|
||||||
SyntaxShape::Table(vec![]),
|
Type::List(Box::new(Type::String)),
|
||||||
"For a record or table input, check strings at the given columns, and replace with result",
|
Type::List(Box::new(Type::String)),
|
||||||
Some('c'),
|
),
|
||||||
)
|
])
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
|
@ -50,14 +44,12 @@ If nothing is found, an empty string will be returned."#
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let args = Arguments {
|
let args = Arguments;
|
||||||
columns: call.get_flag(engine_state, stack, "columns")?,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This doesn't match explicit nulls
|
// This doesn't match explicit nulls
|
||||||
if matches!(input, PipelineData::Empty) {
|
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")),
|
result: Some(Value::test_string("dir")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Show type of a filepath in a column",
|
description: "Show type of a filepaths in a list",
|
||||||
example: "ls | path type -c [ name ]",
|
example: "ls | get name | path type",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,21 +2,6 @@ use nu_test_support::{nu, pipeline};
|
||||||
|
|
||||||
use super::join_path_sep;
|
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]
|
#[test]
|
||||||
fn returns_path_joined_from_list() {
|
fn returns_path_joined_from_list() {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
|
|
|
@ -99,21 +99,6 @@ fn parses_ignoring_extension_gets_stem() {
|
||||||
assert_eq!(actual.out, "spam.tar.gz");
|
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]
|
#[test]
|
||||||
fn parses_into_correct_number_of_columns() {
|
fn parses_into_correct_number_of_columns() {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
|
|
|
@ -25,24 +25,3 @@ fn splits_correctly_single_path() {
|
||||||
|
|
||||||
assert_eq!(actual.out, "spam.txt");
|
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");
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
|
||||||
/// when used in errors.
|
/// when used in errors.
|
||||||
pub fn test_date(val: DateTime<FixedOffset>) -> Value {
|
pub fn test_date(val: DateTime<FixedOffset>) -> Value {
|
||||||
|
|
Loading…
Reference in a new issue