mirror of
https://github.com/nushell/nushell.git
synced 2025-07-01 15:11:52 +02:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
4faaa5310e | |||
c448abd44e | |||
2517588d7d | |||
8fc8fc89aa | |||
b243b3ee1d | |||
28e08afada | |||
7e184b58b2 | |||
589fc0b8ad | |||
f0c7c1b500 | |||
840bd98e01 | |||
a5cdd22bfe | |||
0c7bcae9b1 | |||
ab666c170c | |||
d2213d18fa | |||
82b6300dcb | |||
b69cda9e07 | |||
56adc7c3c6 | |||
2ace20fade | |||
c13fe83784 | |||
6cf8df8685 | |||
86a89404be | |||
0d305d7c3e | |||
ee5bd2b4b3 |
@ -2,7 +2,7 @@
|
||||
|
||||
Welcome to nushell!
|
||||
|
||||
*Note: for a more complete guide see [The nu contributor book](https://github.com/nushell/contributor-book)*
|
||||
*Note: for a more complete guide see [The nu contributor book](https://www.nushell.sh/contributor-book/)*
|
||||
|
||||
For speedy contributions open it in Gitpod, nu will be pre-installed with the latest build in a VSCode like editor all from your browser.
|
||||
|
||||
|
1211
Cargo.lock
generated
1211
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
62
Cargo.toml
62
Cargo.toml
@ -10,7 +10,7 @@ license = "MIT"
|
||||
name = "nu"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
|
||||
[workspace]
|
||||
members = ["crates/*/"]
|
||||
@ -18,35 +18,35 @@ members = ["crates/*/"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { version = "0.28.0", path = "./crates/nu-cli", default-features = false }
|
||||
nu-command = { version = "0.28.0", path = "./crates/nu-command" }
|
||||
nu-data = { version = "0.28.0", path = "./crates/nu-data" }
|
||||
nu-engine = { version = "0.28.0", path = "./crates/nu-engine" }
|
||||
nu-errors = { version = "0.28.0", path = "./crates/nu-errors" }
|
||||
nu-parser = { version = "0.28.0", path = "./crates/nu-parser" }
|
||||
nu-plugin = { version = "0.28.0", path = "./crates/nu-plugin" }
|
||||
nu-protocol = { version = "0.28.0", path = "./crates/nu-protocol" }
|
||||
nu-source = { version = "0.28.0", path = "./crates/nu-source" }
|
||||
nu-value-ext = { version = "0.28.0", path = "./crates/nu-value-ext" }
|
||||
nu-cli = { version = "0.29.0", path = "./crates/nu-cli", default-features = false }
|
||||
nu-command = { version = "0.29.0", path = "./crates/nu-command" }
|
||||
nu-data = { version = "0.29.0", path = "./crates/nu-data" }
|
||||
nu-engine = { version = "0.29.0", path = "./crates/nu-engine" }
|
||||
nu-errors = { version = "0.29.0", path = "./crates/nu-errors" }
|
||||
nu-parser = { version = "0.29.0", path = "./crates/nu-parser" }
|
||||
nu-plugin = { version = "0.29.0", path = "./crates/nu-plugin" }
|
||||
nu-protocol = { version = "0.29.0", path = "./crates/nu-protocol" }
|
||||
nu-source = { version = "0.29.0", path = "./crates/nu-source" }
|
||||
nu-value-ext = { version = "0.29.0", path = "./crates/nu-value-ext" }
|
||||
|
||||
nu_plugin_binaryview = { version = "0.28.0", path = "./crates/nu_plugin_binaryview", optional = true }
|
||||
nu_plugin_chart = { version = "0.28.0", path = "./crates/nu_plugin_chart", optional = true }
|
||||
nu_plugin_fetch = { version = "0.28.0", path = "./crates/nu_plugin_fetch", optional = true }
|
||||
nu_plugin_from_bson = { version = "0.28.0", path = "./crates/nu_plugin_from_bson", optional = true }
|
||||
nu_plugin_from_sqlite = { version = "0.28.0", path = "./crates/nu_plugin_from_sqlite", optional = true }
|
||||
nu_plugin_inc = { version = "0.28.0", path = "./crates/nu_plugin_inc", optional = true }
|
||||
nu_plugin_match = { version = "0.28.0", path = "./crates/nu_plugin_match", optional = true }
|
||||
nu_plugin_post = { version = "0.28.0", path = "./crates/nu_plugin_post", optional = true }
|
||||
nu_plugin_ps = { version = "0.28.0", path = "./crates/nu_plugin_ps", optional = true }
|
||||
nu_plugin_s3 = { version = "0.28.0", path = "./crates/nu_plugin_s3", optional = true }
|
||||
nu_plugin_selector = { version = "0.28.0", path = "./crates/nu_plugin_selector", optional = true }
|
||||
nu_plugin_start = { version = "0.28.0", path = "./crates/nu_plugin_start", optional = true }
|
||||
nu_plugin_sys = { version = "0.28.0", path = "./crates/nu_plugin_sys", optional = true }
|
||||
nu_plugin_textview = { version = "0.28.0", path = "./crates/nu_plugin_textview", optional = true }
|
||||
nu_plugin_to_bson = { version = "0.28.0", path = "./crates/nu_plugin_to_bson", optional = true }
|
||||
nu_plugin_to_sqlite = { version = "0.28.0", path = "./crates/nu_plugin_to_sqlite", optional = true }
|
||||
nu_plugin_tree = { version = "0.28.0", path = "./crates/nu_plugin_tree", optional = true }
|
||||
nu_plugin_xpath = { version = "0.28.0", path = "./crates/nu_plugin_xpath", optional = true }
|
||||
nu_plugin_binaryview = { version = "0.29.0", path = "./crates/nu_plugin_binaryview", optional = true }
|
||||
nu_plugin_chart = { version = "0.29.0", path = "./crates/nu_plugin_chart", optional = true }
|
||||
nu_plugin_fetch = { version = "0.29.0", path = "./crates/nu_plugin_fetch", optional = true }
|
||||
nu_plugin_from_bson = { version = "0.29.0", path = "./crates/nu_plugin_from_bson", optional = true }
|
||||
nu_plugin_from_sqlite = { version = "0.29.0", path = "./crates/nu_plugin_from_sqlite", optional = true }
|
||||
nu_plugin_inc = { version = "0.29.0", path = "./crates/nu_plugin_inc", optional = true }
|
||||
nu_plugin_match = { version = "0.29.0", path = "./crates/nu_plugin_match", optional = true }
|
||||
nu_plugin_post = { version = "0.29.0", path = "./crates/nu_plugin_post", optional = true }
|
||||
nu_plugin_ps = { version = "0.29.0", path = "./crates/nu_plugin_ps", optional = true }
|
||||
nu_plugin_s3 = { version = "0.29.0", path = "./crates/nu_plugin_s3", optional = true }
|
||||
nu_plugin_selector = { version = "0.29.0", path = "./crates/nu_plugin_selector", optional = true }
|
||||
nu_plugin_start = { version = "0.29.0", path = "./crates/nu_plugin_start", optional = true }
|
||||
nu_plugin_sys = { version = "0.29.0", path = "./crates/nu_plugin_sys", optional = true }
|
||||
nu_plugin_textview = { version = "0.29.0", path = "./crates/nu_plugin_textview", optional = true }
|
||||
nu_plugin_to_bson = { version = "0.29.0", path = "./crates/nu_plugin_to_bson", optional = true }
|
||||
nu_plugin_to_sqlite = { version = "0.29.0", path = "./crates/nu_plugin_to_sqlite", optional = true }
|
||||
nu_plugin_tree = { version = "0.29.0", path = "./crates/nu_plugin_tree", optional = true }
|
||||
nu_plugin_xpath = { version = "0.29.0", path = "./crates/nu_plugin_xpath", optional = true }
|
||||
|
||||
# Required to bootstrap the main binary
|
||||
clap = "2.33.3"
|
||||
@ -57,9 +57,10 @@ log = "0.4.14"
|
||||
pretty_env_logger = "0.4.0"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { version = "0.28.0", path = "./crates/nu-test-support" }
|
||||
nu-test-support = { version = "0.29.0", path = "./crates/nu-test-support" }
|
||||
dunce = "1.0.1"
|
||||
serial_test = "0.5.1"
|
||||
hamcrest2 = "0.3.0"
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
@ -84,6 +85,7 @@ which-support = [
|
||||
"nu-cli/which",
|
||||
"nu-command/ichwh",
|
||||
"nu-command/which",
|
||||
"nu-engine/which",
|
||||
]
|
||||
|
||||
default = [
|
||||
|
@ -9,7 +9,7 @@ description = "Library for ANSI terminal colors and styles (bold, underline)"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-ansi-term"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
@ -15,7 +15,7 @@ fn main() {
|
||||
let g = (col * 255 / WIDTH) as u8;
|
||||
let b = 128;
|
||||
|
||||
print!("{}", Style::default().on(Color::RGB(r, g, b)).paint(" "));
|
||||
print!("{}", Style::default().on(Color::Rgb(r, g, b)).paint(" "));
|
||||
}
|
||||
|
||||
println!();
|
||||
|
@ -103,7 +103,7 @@ impl Color {
|
||||
Color::Cyan => write!(f, "36"),
|
||||
Color::White => write!(f, "37"),
|
||||
Color::Fixed(num) => write!(f, "38;5;{}", &num),
|
||||
Color::RGB(r, g, b) => write!(f, "38;2;{};{};{}", &r, &g, &b),
|
||||
Color::Rgb(r, g, b) => write!(f, "38;2;{};{};{}", &r, &g, &b),
|
||||
Color::DarkGray => write!(f, "90"),
|
||||
Color::LightRed => write!(f, "91"),
|
||||
Color::LightGreen => write!(f, "92"),
|
||||
@ -128,7 +128,7 @@ impl Color {
|
||||
Color::Cyan => write!(f, "46"),
|
||||
Color::White => write!(f, "47"),
|
||||
Color::Fixed(num) => write!(f, "48;5;{}", &num),
|
||||
Color::RGB(r, g, b) => write!(f, "48;2;{};{};{}", &r, &g, &b),
|
||||
Color::Rgb(r, g, b) => write!(f, "48;2;{};{};{}", &r, &g, &b),
|
||||
Color::DarkGray => write!(f, "100"),
|
||||
Color::LightRed => write!(f, "101"),
|
||||
Color::LightGreen => write!(f, "102"),
|
||||
@ -372,10 +372,10 @@ mod test {
|
||||
test!(fixed: Fixed(100); "hi" => "\x1B[38;5;100mhi\x1B[0m");
|
||||
test!(fixed_on_purple: Fixed(100).on(Purple); "hi" => "\x1B[45;38;5;100mhi\x1B[0m");
|
||||
test!(fixed_on_fixed: Fixed(100).on(Fixed(200)); "hi" => "\x1B[48;5;200;38;5;100mhi\x1B[0m");
|
||||
test!(rgb: RGB(70,130,180); "hi" => "\x1B[38;2;70;130;180mhi\x1B[0m");
|
||||
test!(rgb_on_blue: RGB(70,130,180).on(Blue); "hi" => "\x1B[44;38;2;70;130;180mhi\x1B[0m");
|
||||
test!(blue_on_rgb: Blue.on(RGB(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m");
|
||||
test!(rgb_on_rgb: RGB(70,130,180).on(RGB(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m");
|
||||
test!(rgb: Rgb(70,130,180); "hi" => "\x1B[38;2;70;130;180mhi\x1B[0m");
|
||||
test!(rgb_on_blue: Rgb(70,130,180).on(Blue); "hi" => "\x1B[44;38;2;70;130;180mhi\x1B[0m");
|
||||
test!(blue_on_rgb: Blue.on(Rgb(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m");
|
||||
test!(rgb_on_rgb: Rgb(70,130,180).on(Rgb(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m");
|
||||
test!(bold: Style::new().bold(); "hi" => "\x1B[1mhi\x1B[0m");
|
||||
test!(underline: Style::new().underline(); "hi" => "\x1B[4mhi\x1B[0m");
|
||||
test!(bunderline: Style::new().bold().underline(); "hi" => "\x1B[1;4mhi\x1B[0m");
|
||||
|
@ -112,7 +112,7 @@ mod test {
|
||||
test!(both: style().bold().italic() => "Style { bold, italic }");
|
||||
|
||||
test!(red: Red.normal() => "Style { fg(Red) }");
|
||||
test!(redblue: Red.normal().on(RGB(3, 2, 4)) => "Style { fg(Red), on(RGB(3, 2, 4)) }");
|
||||
test!(redblue: Red.normal().on(Rgb(3, 2, 4)) => "Style { fg(Red), on(Rgb(3, 2, 4)) }");
|
||||
|
||||
test!(everything:
|
||||
Red.on(Blue).blink().bold().dimmed().hidden().italic().reverse().strikethrough().underline() =>
|
||||
|
@ -11,7 +11,7 @@ use std::ops::Deref;
|
||||
/// display that string. `ANSIString` and `ANSIByteString` are aliases for
|
||||
/// this type on `str` and `\[u8]`, respectively.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct ANSIGenericString<'a, S: 'a + ToOwned + ?Sized>
|
||||
pub struct AnsiGenericString<'a, S: 'a + ToOwned + ?Sized>
|
||||
where
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
{
|
||||
@ -30,12 +30,12 @@ where
|
||||
/// let clone_string = plain_string.clone();
|
||||
/// assert_eq!(clone_string, plain_string);
|
||||
/// ```
|
||||
impl<'a, S: 'a + ToOwned + ?Sized> Clone for ANSIGenericString<'a, S>
|
||||
impl<'a, S: 'a + ToOwned + ?Sized> Clone for AnsiGenericString<'a, S>
|
||||
where
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
{
|
||||
fn clone(&self) -> ANSIGenericString<'a, S> {
|
||||
ANSIGenericString {
|
||||
fn clone(&self) -> AnsiGenericString<'a, S> {
|
||||
AnsiGenericString {
|
||||
style: self.style,
|
||||
string: self.string.clone(),
|
||||
}
|
||||
@ -85,26 +85,26 @@ where
|
||||
/// let plain_string = ANSIString::from("a plain string");
|
||||
/// assert_eq!(&*plain_string, "a plain string");
|
||||
/// ```
|
||||
pub type ANSIString<'a> = ANSIGenericString<'a, str>;
|
||||
pub type AnsiString<'a> = AnsiGenericString<'a, str>;
|
||||
|
||||
/// An `ANSIByteString` represents a formatted series of bytes. Use
|
||||
/// `ANSIByteString` when styling text with an unknown encoding.
|
||||
pub type ANSIByteString<'a> = ANSIGenericString<'a, [u8]>;
|
||||
/// An `AnsiByteString` represents a formatted series of bytes. Use
|
||||
/// `AnsiByteString` when styling text with an unknown encoding.
|
||||
pub type AnsiByteString<'a> = AnsiGenericString<'a, [u8]>;
|
||||
|
||||
impl<'a, I, S: 'a + ToOwned + ?Sized> From<I> for ANSIGenericString<'a, S>
|
||||
impl<'a, I, S: 'a + ToOwned + ?Sized> From<I> for AnsiGenericString<'a, S>
|
||||
where
|
||||
I: Into<Cow<'a, S>>,
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
{
|
||||
fn from(input: I) -> ANSIGenericString<'a, S> {
|
||||
ANSIGenericString {
|
||||
fn from(input: I) -> AnsiGenericString<'a, S> {
|
||||
AnsiGenericString {
|
||||
string: input.into(),
|
||||
style: Style::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericString<'a, S>
|
||||
impl<'a, S: 'a + ToOwned + ?Sized> AnsiGenericString<'a, S>
|
||||
where
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
{
|
||||
@ -119,7 +119,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: 'a + ToOwned + ?Sized> Deref for ANSIGenericString<'a, S>
|
||||
impl<'a, S: 'a + ToOwned + ?Sized> Deref for AnsiGenericString<'a, S>
|
||||
where
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
{
|
||||
@ -130,32 +130,32 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of `ANSIGenericString`s collected together, in order to be
|
||||
/// A set of `AnsiGenericStrings`s collected together, in order to be
|
||||
/// written with a minimum of control characters.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct ANSIGenericStrings<'a, S: 'a + ToOwned + ?Sized>(pub &'a [ANSIGenericString<'a, S>])
|
||||
pub struct AnsiGenericStrings<'a, S: 'a + ToOwned + ?Sized>(pub &'a [AnsiGenericString<'a, S>])
|
||||
where
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
S: PartialEq;
|
||||
|
||||
/// A set of `ANSIString`s collected together, in order to be written with a
|
||||
/// A set of `AnsiString`s collected together, in order to be written with a
|
||||
/// minimum of control characters.
|
||||
pub type ANSIStrings<'a> = ANSIGenericStrings<'a, str>;
|
||||
pub type AnsiStrings<'a> = AnsiGenericStrings<'a, str>;
|
||||
|
||||
/// A function to construct an `ANSIStrings` instance.
|
||||
/// A function to construct an `AnsiStrings` instance.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn ANSIStrings<'a>(arg: &'a [ANSIString<'a>]) -> ANSIStrings<'a> {
|
||||
ANSIGenericStrings(arg)
|
||||
pub fn AnsiStrings<'a>(arg: &'a [AnsiString<'a>]) -> AnsiStrings<'a> {
|
||||
AnsiGenericStrings(arg)
|
||||
}
|
||||
|
||||
/// A set of `ANSIByteString`s collected together, in order to be
|
||||
/// A set of `AnsiByteString`s collected together, in order to be
|
||||
/// written with a minimum of control characters.
|
||||
pub type ANSIByteStrings<'a> = ANSIGenericStrings<'a, [u8]>;
|
||||
pub type AnsiByteStrings<'a> = AnsiGenericStrings<'a, [u8]>;
|
||||
|
||||
/// A function to construct an `ANSIByteStrings` instance.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn ANSIByteStrings<'a>(arg: &'a [ANSIByteString<'a>]) -> ANSIByteStrings<'a> {
|
||||
ANSIGenericStrings(arg)
|
||||
pub fn ANSIByteStrings<'a>(arg: &'a [AnsiByteString<'a>]) -> AnsiByteStrings<'a> {
|
||||
AnsiGenericStrings(arg)
|
||||
}
|
||||
|
||||
// ---- paint functions ----
|
||||
@ -163,12 +163,12 @@ pub fn ANSIByteStrings<'a>(arg: &'a [ANSIByteString<'a>]) -> ANSIByteStrings<'a>
|
||||
impl Style {
|
||||
/// Paints the given text with this color, returning an ANSI string.
|
||||
#[must_use]
|
||||
pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S>
|
||||
pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> AnsiGenericString<'a, S>
|
||||
where
|
||||
I: Into<Cow<'a, S>>,
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
{
|
||||
ANSIGenericString {
|
||||
AnsiGenericString {
|
||||
string: input.into(),
|
||||
style: self,
|
||||
}
|
||||
@ -185,12 +185,12 @@ impl Color {
|
||||
/// println!("{}", Blue.paint("da ba dee"));
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S>
|
||||
pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> AnsiGenericString<'a, S>
|
||||
where
|
||||
I: Into<Cow<'a, S>>,
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
{
|
||||
ANSIGenericString {
|
||||
AnsiGenericString {
|
||||
string: input.into(),
|
||||
style: self.normal(),
|
||||
}
|
||||
@ -199,14 +199,14 @@ impl Color {
|
||||
|
||||
// ---- writers for individual ANSI strings ----
|
||||
|
||||
impl<'a> fmt::Display for ANSIString<'a> {
|
||||
impl<'a> fmt::Display for AnsiString<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let w: &mut dyn fmt::Write = f;
|
||||
self.write_to_any(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ANSIByteString<'a> {
|
||||
impl<'a> AnsiByteString<'a> {
|
||||
/// Write an `ANSIByteString` to an `io::Write`. This writes the escape
|
||||
/// sequences for the associated `Style` around the bytes.
|
||||
pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
@ -215,7 +215,7 @@ impl<'a> ANSIByteString<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericString<'a, S>
|
||||
impl<'a, S: 'a + ToOwned + ?Sized> AnsiGenericString<'a, S>
|
||||
where
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
&'a S: AsRef<[u8]>,
|
||||
@ -229,14 +229,14 @@ where
|
||||
|
||||
// ---- writers for combined ANSI strings ----
|
||||
|
||||
impl<'a> fmt::Display for ANSIStrings<'a> {
|
||||
impl<'a> fmt::Display for AnsiStrings<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let f: &mut dyn fmt::Write = f;
|
||||
self.write_to_any(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ANSIByteStrings<'a> {
|
||||
impl<'a> AnsiByteStrings<'a> {
|
||||
/// Write `ANSIByteStrings` to an `io::Write`. This writes the minimal
|
||||
/// escape sequences for the associated `Style`s around each set of
|
||||
/// bytes.
|
||||
@ -246,7 +246,7 @@ impl<'a> ANSIByteStrings<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: 'a + ToOwned + ?Sized + PartialEq> ANSIGenericStrings<'a, S>
|
||||
impl<'a, S: 'a + ToOwned + ?Sized + PartialEq> AnsiGenericStrings<'a, S>
|
||||
where
|
||||
<S as ToOwned>::Owned: fmt::Debug,
|
||||
&'a S: AsRef<[u8]>,
|
||||
@ -289,7 +289,7 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
pub use super::super::ANSIStrings;
|
||||
pub use super::super::AnsiStrings;
|
||||
pub use crate::style::Color::*;
|
||||
pub use crate::style::Style;
|
||||
|
||||
@ -297,7 +297,7 @@ mod tests {
|
||||
fn no_control_codes_for_plain() {
|
||||
let one = Style::default().paint("one");
|
||||
let two = Style::default().paint("two");
|
||||
let output = format!("{}", ANSIStrings(&[one, two]));
|
||||
let output = format!("{}", AnsiStrings(&[one, two]));
|
||||
assert_eq!(&*output, "onetwo");
|
||||
}
|
||||
}
|
||||
|
@ -365,7 +365,7 @@ pub enum Color {
|
||||
Fixed(u8),
|
||||
|
||||
/// A 24-bit RGB color, as specified by ISO-8613-3.
|
||||
RGB(u8, u8, u8),
|
||||
Rgb(u8, u8, u8),
|
||||
}
|
||||
|
||||
impl Color {
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::display::{ANSIString, ANSIStrings};
|
||||
use crate::display::{AnsiString, AnsiStrings};
|
||||
use std::ops::Deref;
|
||||
|
||||
/// Return a substring of the given ANSIStrings sequence, while keeping the formatting.
|
||||
pub fn sub_string<'a>(
|
||||
start: usize,
|
||||
len: usize,
|
||||
strs: &ANSIStrings<'a>,
|
||||
) -> Vec<ANSIString<'static>> {
|
||||
strs: &AnsiStrings<'a>,
|
||||
) -> Vec<AnsiString<'static>> {
|
||||
let mut vec = Vec::new();
|
||||
let mut pos = start;
|
||||
let mut len_rem = len;
|
||||
@ -39,7 +39,7 @@ pub fn sub_string<'a>(
|
||||
}
|
||||
|
||||
/// Return a concatenated copy of `strs` without the formatting, as an allocated `String`.
|
||||
pub fn unstyle(strs: &ANSIStrings) -> String {
|
||||
pub fn unstyle(strs: &AnsiStrings) -> String {
|
||||
let mut s = String::new();
|
||||
|
||||
for i in strs.0.iter() {
|
||||
@ -50,7 +50,7 @@ pub fn unstyle(strs: &ANSIStrings) -> String {
|
||||
}
|
||||
|
||||
/// Return the unstyled length of ANSIStrings. This is equaivalent to `unstyle(strs).len()`.
|
||||
pub fn unstyled_len(strs: &ANSIStrings) -> usize {
|
||||
pub fn unstyled_len(strs: &AnsiStrings) -> usize {
|
||||
let mut l = 0;
|
||||
for i in strs.0.iter() {
|
||||
l += i.deref().len();
|
||||
@ -70,7 +70,7 @@ mod test {
|
||||
Red.paint("-second"),
|
||||
White.paint("-third"),
|
||||
];
|
||||
let a = ANSIStrings(&l);
|
||||
let a = AnsiStrings(&l);
|
||||
assert_eq!(unstyle(&a), "first-second-third");
|
||||
assert_eq!(unstyled_len(&a), 18);
|
||||
|
||||
|
@ -5,26 +5,26 @@ description = "CLI for nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
nu-command = { version = "0.28.0", path = "../nu-command" }
|
||||
nu-data = { version = "0.28.0", path = "../nu-data" }
|
||||
nu-engine = { version = "0.28.0", path = "../nu-engine" }
|
||||
nu-errors = { version = "0.28.0", path = "../nu-errors" }
|
||||
nu-json = { version = "0.28.0", path = "../nu-json" }
|
||||
nu-parser = { version = "0.28.0", path = "../nu-parser" }
|
||||
nu-plugin = { version = "0.28.0", path = "../nu-plugin" }
|
||||
nu-protocol = { version = "0.28.0", path = "../nu-protocol" }
|
||||
nu-source = { version = "0.28.0", path = "../nu-source" }
|
||||
nu-stream = { version = "0.28.0", path = "../nu-stream" }
|
||||
nu-table = { version = "0.28.0", path = "../nu-table" }
|
||||
nu-test-support = { version = "0.28.0", path = "../nu-test-support" }
|
||||
nu-value-ext = { version = "0.28.0", path = "../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.28.0", path = "../nu-ansi-term" }
|
||||
nu-command = { version = "0.29.0", path = "../nu-command" }
|
||||
nu-data = { version = "0.29.0", path = "../nu-data" }
|
||||
nu-engine = { version = "0.29.0", path = "../nu-engine" }
|
||||
nu-errors = { version = "0.29.0", path = "../nu-errors" }
|
||||
nu-json = { version = "0.29.0", path = "../nu-json" }
|
||||
nu-parser = { version = "0.29.0", path = "../nu-parser" }
|
||||
nu-plugin = { version = "0.29.0", path = "../nu-plugin" }
|
||||
nu-protocol = { version = "0.29.0", path = "../nu-protocol" }
|
||||
nu-source = { version = "0.29.0", path = "../nu-source" }
|
||||
nu-stream = { version = "0.29.0", path = "../nu-stream" }
|
||||
nu-table = { version = "0.29.0", path = "../nu-table" }
|
||||
nu-test-support = { version = "0.29.0", path = "../nu-test-support" }
|
||||
nu-value-ext = { version = "0.29.0", path = "../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.29.0", path = "../nu-ansi-term" }
|
||||
|
||||
Inflector = "0.11"
|
||||
arboard = { version = "1.1.0", optional = true }
|
||||
@ -77,7 +77,7 @@ rayon = "1.5.0"
|
||||
regex = "1.4.3"
|
||||
roxmltree = "0.14.0"
|
||||
rust-embed = "5.9.0"
|
||||
rustyline = { version = "6.3.0", optional = true }
|
||||
rustyline = { version = "8.0.0", optional = true }
|
||||
serde = { version = "1.0.123", features = ["derive"] }
|
||||
serde_bytes = "0.11.5"
|
||||
serde_ini = "0.2.0"
|
||||
|
@ -1,12 +1,9 @@
|
||||
use crate::line_editor::configure_ctrl_c;
|
||||
use nu_command::commands::default_context::create_default_context;
|
||||
#[allow(unused_imports)]
|
||||
use nu_command::maybe_print_errors;
|
||||
use nu_engine::run_block;
|
||||
use nu_engine::EvaluationContext;
|
||||
use nu_engine::{evaluation_context, run_block, script::run_script_standalone, EvaluationContext};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use nu_command::script::{process_script, LineResult};
|
||||
pub(crate) use nu_engine::script::{process_script, LineResult};
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
use crate::line_editor::{
|
||||
@ -16,13 +13,13 @@ use crate::line_editor::{
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use nu_data::config;
|
||||
use nu_source::{Tag, Text};
|
||||
use nu_data::config::{Conf, NuConfig};
|
||||
use nu_source::{AnchorLocation, Tag, Text};
|
||||
use nu_stream::InputStream;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
#[allow(unused_imports)]
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use nu_command::script::{print_err, run_script_standalone};
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
use rustyline::{self, error::ReadlineError};
|
||||
|
||||
@ -36,6 +33,81 @@ use std::error::Error;
|
||||
use std::iter::Iterator;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Options {
|
||||
pub config: Option<OsString>,
|
||||
pub history: Option<PathBuf>,
|
||||
pub save_history: bool,
|
||||
pub stdin: bool,
|
||||
pub scripts: Vec<NuScript>,
|
||||
}
|
||||
|
||||
impl Default for Options {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Options {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
config: None,
|
||||
history: None,
|
||||
save_history: true,
|
||||
stdin: false,
|
||||
scripts: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn history(&self, block: impl FnOnce(&std::path::Path)) {
|
||||
if !self.save_history {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(file) = &self.history {
|
||||
block(&file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NuScript {
|
||||
pub filepath: Option<OsString>,
|
||||
pub contents: String,
|
||||
}
|
||||
|
||||
impl NuScript {
|
||||
pub fn code<'a>(content: impl Iterator<Item = &'a str>) -> Result<Self, ShellError> {
|
||||
let text = content
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
Ok(Self {
|
||||
filepath: None,
|
||||
contents: text,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_code(&self) -> &str {
|
||||
&self.contents
|
||||
}
|
||||
|
||||
pub fn source_file(path: &OsStr) -> Result<Self, ShellError> {
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
let path = path.to_os_string();
|
||||
let mut file = File::open(&path)?;
|
||||
let mut buffer = String::new();
|
||||
|
||||
file.read_to_string(&mut buffer)?;
|
||||
|
||||
Ok(Self {
|
||||
filepath: Some(path),
|
||||
contents: buffer,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn search_paths() -> Vec<std::path::PathBuf> {
|
||||
use std::env;
|
||||
|
||||
@ -65,12 +137,9 @@ pub fn search_paths() -> Vec<std::path::PathBuf> {
|
||||
search_paths
|
||||
}
|
||||
|
||||
pub async fn run_script_file(
|
||||
file_contents: String,
|
||||
redirect_stdin: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut syncer = EnvironmentSyncer::new();
|
||||
pub async fn run_script_file(mut options: Options) -> Result<(), Box<dyn Error>> {
|
||||
let mut context = create_default_context(false)?;
|
||||
let mut syncer = create_environment_syncer(&context, &mut options);
|
||||
let config = syncer.get_config();
|
||||
|
||||
context.configure(&config, |_, ctx| {
|
||||
@ -79,7 +148,7 @@ pub async fn run_script_file(
|
||||
syncer.sync_path_vars(ctx);
|
||||
|
||||
if let Err(reason) = syncer.autoenv(ctx) {
|
||||
print_err(reason, &Text::from(""), ctx);
|
||||
ctx.with_host(|host| host.print_err(reason, &Text::from("")));
|
||||
}
|
||||
|
||||
let _ = register_plugins(ctx);
|
||||
@ -88,15 +157,62 @@ pub async fn run_script_file(
|
||||
|
||||
let _ = run_startup_commands(&mut context, &config).await;
|
||||
|
||||
run_script_standalone(file_contents, redirect_stdin, &context, true).await?;
|
||||
let script = options
|
||||
.scripts
|
||||
.get(0)
|
||||
.ok_or_else(|| ShellError::unexpected("Nu source code not available"))?;
|
||||
|
||||
run_script_standalone(script.get_code().to_string(), options.stdin, &context, true).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The entry point for the CLI. Will register all known internal commands, load experimental commands, load plugins, then prepare the prompt and line reader for input.
|
||||
fn create_environment_syncer(
|
||||
context: &EvaluationContext,
|
||||
options: &mut Options,
|
||||
) -> EnvironmentSyncer {
|
||||
let configuration = match &options.config {
|
||||
Some(config_file) => {
|
||||
let location = Some(AnchorLocation::File(
|
||||
config_file.to_string_lossy().to_string(),
|
||||
));
|
||||
|
||||
let tag = Tag::unknown().anchored(location);
|
||||
|
||||
context.scope.add_var(
|
||||
"config-path",
|
||||
UntaggedValue::filepath(PathBuf::from(&config_file)).into_value(tag),
|
||||
);
|
||||
|
||||
NuConfig::with(Some(config_file.into()))
|
||||
}
|
||||
None => NuConfig::new(),
|
||||
};
|
||||
|
||||
let history_path = configuration.history_path();
|
||||
options.history = Some(history_path.clone());
|
||||
|
||||
let location = Some(AnchorLocation::File(
|
||||
history_path.to_string_lossy().to_string(),
|
||||
));
|
||||
|
||||
let tag = Tag::unknown().anchored(location);
|
||||
|
||||
context.scope.add_var(
|
||||
"history-path",
|
||||
UntaggedValue::filepath(history_path).into_value(tag),
|
||||
);
|
||||
|
||||
EnvironmentSyncer::with_config(Box::new(configuration))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
let mut syncer = EnvironmentSyncer::new();
|
||||
pub async fn cli(
|
||||
mut context: EvaluationContext,
|
||||
mut options: Options,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut syncer = create_environment_syncer(&context, &mut options);
|
||||
|
||||
let configuration = syncer.get_config();
|
||||
|
||||
let mut rl = default_rustyline_editor_configuration();
|
||||
@ -107,7 +223,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
syncer.sync_path_vars(ctx);
|
||||
|
||||
if let Err(reason) = syncer.autoenv(ctx) {
|
||||
print_err(reason, &Text::from(""), ctx);
|
||||
ctx.with_host(|host| host.print_err(reason, &Text::from("")));
|
||||
}
|
||||
|
||||
let _ = configure_ctrl_c(ctx);
|
||||
@ -134,8 +250,9 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
// Give ourselves a scope to work in
|
||||
context.scope.enter_scope();
|
||||
|
||||
let history_path = nu_engine::history_path(&configuration);
|
||||
let _ = rl.load_history(&history_path);
|
||||
options.history(|file| {
|
||||
let _ = rl.load_history(&file);
|
||||
});
|
||||
|
||||
let mut session_text = String::new();
|
||||
let mut line_start: usize = 0;
|
||||
@ -171,6 +288,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
let prompt_line = prompt.as_string()?;
|
||||
|
||||
context.scope.enter_scope();
|
||||
|
||||
let (mut prompt_block, err) = nu_parser::parse(&prompt_line, 0, &context.scope);
|
||||
|
||||
prompt_block.set_redirect(ExternalRedirection::Stdout);
|
||||
@ -180,8 +298,6 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
|
||||
format!("\x1b[32m{}{}\x1b[m> ", cwd, current_branch())
|
||||
} else {
|
||||
// let env = context.get_env();
|
||||
|
||||
let run_result = run_block(&prompt_block, &context, InputStream::empty()).await;
|
||||
context.scope.exit_scope();
|
||||
|
||||
@ -189,7 +305,10 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
Ok(result) => match result.collect_string(Tag::unknown()).await {
|
||||
Ok(string_result) => {
|
||||
let errors = context.get_errors();
|
||||
maybe_print_errors(&context, Text::from(prompt_line));
|
||||
evaluation_context::maybe_print_errors(
|
||||
&context,
|
||||
Text::from(prompt_line),
|
||||
);
|
||||
context.clear_errors();
|
||||
|
||||
if !errors.is_empty() {
|
||||
@ -199,14 +318,14 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
crate::cli::print_err(e, &Text::from(prompt_line), &context);
|
||||
context.host.lock().print_err(e, &Text::from(prompt_line));
|
||||
context.clear_errors();
|
||||
|
||||
"> ".to_string()
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
crate::cli::print_err(e, &Text::from(prompt_line), &context);
|
||||
context.host.lock().print_err(e, &Text::from(prompt_line));
|
||||
context.clear_errors();
|
||||
|
||||
"> ".to_string()
|
||||
@ -274,7 +393,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
if let Err(reason) = syncer.autoenv(ctx) {
|
||||
print_err(reason, &Text::from(""), ctx);
|
||||
ctx.with_host(|host| host.print_err(reason, &Text::from("")));
|
||||
}
|
||||
|
||||
let _ = configure_rustyline_editor(&mut rl, config);
|
||||
@ -282,28 +401,33 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
|
||||
match line {
|
||||
LineResult::Success(line) => {
|
||||
rl.add_history_entry(&line);
|
||||
let _ = rl.save_history(&history_path);
|
||||
maybe_print_errors(&context, Text::from(session_text.clone()));
|
||||
options.history(|file| {
|
||||
rl.add_history_entry(&line);
|
||||
let _ = rl.save_history(&file);
|
||||
});
|
||||
|
||||
evaluation_context::maybe_print_errors(&context, Text::from(session_text.clone()));
|
||||
}
|
||||
|
||||
LineResult::ClearHistory => {
|
||||
rl.clear_history();
|
||||
let _ = rl.save_history(&history_path);
|
||||
options.history(|file| {
|
||||
rl.clear_history();
|
||||
let _ = rl.save_history(&file);
|
||||
});
|
||||
}
|
||||
|
||||
LineResult::Error(line, err) => {
|
||||
rl.add_history_entry(&line);
|
||||
let _ = rl.save_history(&history_path);
|
||||
LineResult::Error(line, reason) => {
|
||||
options.history(|file| {
|
||||
rl.add_history_entry(&line);
|
||||
let _ = rl.save_history(&file);
|
||||
});
|
||||
|
||||
print_err(err, &Text::from(session_text.clone()), &context);
|
||||
|
||||
maybe_print_errors(&context, Text::from(session_text.clone()));
|
||||
context.with_host(|host| host.print_err(reason, &Text::from(session_text.clone())));
|
||||
}
|
||||
|
||||
LineResult::CtrlC => {
|
||||
let config_ctrlc_exit = config::config(Tag::unknown())?
|
||||
.get("ctrlc_exit")
|
||||
let config_ctrlc_exit = configuration
|
||||
.var("ctrlc_exit")
|
||||
.map(|s| s.value.is_true())
|
||||
.unwrap_or(false); // default behavior is to allow CTRL-C spamming similar to other shells
|
||||
|
||||
@ -312,7 +436,10 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
if ctrlcbreak {
|
||||
let _ = rl.save_history(&history_path);
|
||||
options.history(|file| {
|
||||
let _ = rl.save_history(&file);
|
||||
});
|
||||
|
||||
std::process::exit(0);
|
||||
} else {
|
||||
context.with_host(|host| host.stdout("CTRL-C pressed (again to quit)"));
|
||||
@ -336,7 +463,9 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
// we are ok if we can not save history
|
||||
let _ = rl.save_history(&history_path);
|
||||
options.history(|file| {
|
||||
let _ = rl.save_history(&file);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -426,14 +555,14 @@ fn current_branch() -> String {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nu_engine::basic_evaluation_context;
|
||||
use nu_engine::EvaluationContext;
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_parse(data: String) -> bool {
|
||||
let (tokens, err) = nu_parser::lex(&data, 0);
|
||||
let (lite_block, err2) = nu_parser::parse_block(tokens);
|
||||
if err.is_none() && err2.is_none() {
|
||||
let context = basic_evaluation_context().unwrap();
|
||||
let context = EvaluationContext::basic().unwrap();
|
||||
let _ = nu_parser::classify_block(&lite_block, &context.scope);
|
||||
}
|
||||
true
|
||||
|
@ -15,7 +15,8 @@ pub struct PathSuggestion {
|
||||
impl PathCompleter {
|
||||
pub fn path_suggestions(&self, partial: &str, matcher: &dyn Matcher) -> Vec<PathSuggestion> {
|
||||
let expanded = nu_parser::expand_ndots(partial);
|
||||
let expanded = expanded.as_ref();
|
||||
let expanded = expanded.replace(std::path::is_separator, &SEP.to_string());
|
||||
let expanded: &str = expanded.as_ref();
|
||||
|
||||
let (base_dir_name, partial) = match expanded.rfind(SEP) {
|
||||
Some(pos) => expanded.split_at(pos + SEP.len_utf8()),
|
||||
|
12
crates/nu-cli/src/env/environment_syncer.rs
vendored
12
crates/nu-cli/src/env/environment_syncer.rs
vendored
@ -163,8 +163,8 @@ mod tests {
|
||||
use super::EnvironmentSyncer;
|
||||
use indexmap::IndexMap;
|
||||
use nu_data::config::tests::FakeConfig;
|
||||
use nu_engine::basic_evaluation_context;
|
||||
use nu_engine::Env;
|
||||
use nu_engine::EvaluationContext;
|
||||
use nu_errors::ShellError;
|
||||
use nu_test_support::fs::Stub::FileWithContent;
|
||||
use nu_test_support::playground::Playground;
|
||||
@ -179,7 +179,7 @@ mod tests {
|
||||
#[test]
|
||||
fn syncs_env_if_new_env_entry_is_added_to_an_existing_configuration() -> Result<(), ShellError>
|
||||
{
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let mut expected = IndexMap::new();
|
||||
@ -282,7 +282,7 @@ mod tests {
|
||||
#[test]
|
||||
fn syncs_env_if_new_env_entry_in_session_is_not_in_configuration_file() -> Result<(), ShellError>
|
||||
{
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let mut expected = IndexMap::new();
|
||||
@ -381,7 +381,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn nu_envs_have_higher_priority_and_does_not_get_overwritten() -> Result<(), ShellError> {
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let mut expected = IndexMap::new();
|
||||
@ -457,7 +457,7 @@ mod tests {
|
||||
#[test]
|
||||
fn syncs_path_if_new_path_entry_in_session_is_not_in_configuration_file(
|
||||
) -> Result<(), ShellError> {
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let expected = std::env::join_paths(vec![
|
||||
@ -544,7 +544,7 @@ mod tests {
|
||||
#[test]
|
||||
fn nu_paths_have_higher_priority_and_new_paths_get_appended_to_the_end(
|
||||
) -> Result<(), ShellError> {
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let expected = std::env::join_paths(vec![
|
||||
|
@ -1,38 +1,64 @@
|
||||
use rustyline::{KeyCode, Modifiers};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
fn convert_keypress(keypress: KeyPress) -> rustyline::KeyPress {
|
||||
match keypress {
|
||||
KeyPress::UnknownEscSeq => rustyline::KeyPress::UnknownEscSeq,
|
||||
KeyPress::Backspace => rustyline::KeyPress::Backspace,
|
||||
KeyPress::BackTab => rustyline::KeyPress::BackTab,
|
||||
KeyPress::BracketedPasteStart => rustyline::KeyPress::BracketedPasteStart,
|
||||
KeyPress::BracketedPasteEnd => rustyline::KeyPress::BracketedPasteEnd,
|
||||
KeyPress::Char(c) => rustyline::KeyPress::Char(c),
|
||||
KeyPress::ControlDown => rustyline::KeyPress::ControlDown,
|
||||
KeyPress::ControlLeft => rustyline::KeyPress::ControlLeft,
|
||||
KeyPress::ControlRight => rustyline::KeyPress::ControlRight,
|
||||
KeyPress::ControlUp => rustyline::KeyPress::ControlUp,
|
||||
KeyPress::Ctrl(c) => rustyline::KeyPress::Ctrl(c),
|
||||
KeyPress::Delete => rustyline::KeyPress::Delete,
|
||||
KeyPress::Down => rustyline::KeyPress::Down,
|
||||
KeyPress::End => rustyline::KeyPress::End,
|
||||
KeyPress::Enter => rustyline::KeyPress::Enter,
|
||||
KeyPress::Esc => rustyline::KeyPress::Esc,
|
||||
KeyPress::F(u) => rustyline::KeyPress::F(u),
|
||||
KeyPress::Home => rustyline::KeyPress::Home,
|
||||
KeyPress::Insert => rustyline::KeyPress::Insert,
|
||||
KeyPress::Left => rustyline::KeyPress::Left,
|
||||
KeyPress::Meta(c) => rustyline::KeyPress::Meta(c),
|
||||
KeyPress::Null => rustyline::KeyPress::Null,
|
||||
KeyPress::PageDown => rustyline::KeyPress::PageDown,
|
||||
KeyPress::PageUp => rustyline::KeyPress::PageUp,
|
||||
KeyPress::Right => rustyline::KeyPress::Right,
|
||||
KeyPress::ShiftDown => rustyline::KeyPress::ShiftDown,
|
||||
KeyPress::ShiftLeft => rustyline::KeyPress::ShiftLeft,
|
||||
KeyPress::ShiftRight => rustyline::KeyPress::ShiftRight,
|
||||
KeyPress::ShiftUp => rustyline::KeyPress::ShiftUp,
|
||||
KeyPress::Tab => rustyline::KeyPress::Tab,
|
||||
KeyPress::Up => rustyline::KeyPress::Up,
|
||||
pub fn convert_keyevent(key_event: KeyEvent) -> rustyline::KeyEvent {
|
||||
match key_event {
|
||||
KeyEvent::UnknownEscSeq => convert_to_rl_keyevent(rustyline::KeyCode::UnknownEscSeq, None),
|
||||
KeyEvent::Backspace => convert_to_rl_keyevent(rustyline::KeyCode::Backspace, None),
|
||||
KeyEvent::BackTab => convert_to_rl_keyevent(rustyline::KeyCode::BackTab, None),
|
||||
KeyEvent::BracketedPasteStart => {
|
||||
convert_to_rl_keyevent(rustyline::KeyCode::BracketedPasteStart, None)
|
||||
}
|
||||
KeyEvent::BracketedPasteEnd => {
|
||||
convert_to_rl_keyevent(rustyline::KeyCode::BracketedPasteEnd, None)
|
||||
}
|
||||
KeyEvent::Char(c) => convert_to_rl_keyevent(rustyline::KeyCode::Char(c), None),
|
||||
KeyEvent::ControlDown => {
|
||||
convert_to_rl_keyevent(rustyline::KeyCode::Down, Some(Modifiers::CTRL))
|
||||
}
|
||||
KeyEvent::ControlLeft => {
|
||||
convert_to_rl_keyevent(rustyline::KeyCode::Left, Some(Modifiers::CTRL))
|
||||
}
|
||||
KeyEvent::ControlRight => {
|
||||
convert_to_rl_keyevent(rustyline::KeyCode::Right, Some(Modifiers::CTRL))
|
||||
}
|
||||
KeyEvent::ControlUp => {
|
||||
convert_to_rl_keyevent(rustyline::KeyCode::Up, Some(Modifiers::CTRL))
|
||||
}
|
||||
KeyEvent::Ctrl(c) => rustyline::KeyEvent::ctrl(c),
|
||||
KeyEvent::Delete => convert_to_rl_keyevent(rustyline::KeyCode::Delete, None),
|
||||
KeyEvent::Down => convert_to_rl_keyevent(rustyline::KeyCode::Down, None),
|
||||
KeyEvent::End => convert_to_rl_keyevent(rustyline::KeyCode::End, None),
|
||||
KeyEvent::Enter => convert_to_rl_keyevent(rustyline::KeyCode::Enter, None),
|
||||
KeyEvent::Esc => convert_to_rl_keyevent(rustyline::KeyCode::Esc, None),
|
||||
KeyEvent::F(u) => convert_to_rl_keyevent(rustyline::KeyCode::F(u), None),
|
||||
KeyEvent::Home => convert_to_rl_keyevent(rustyline::KeyCode::Home, None),
|
||||
KeyEvent::Insert => convert_to_rl_keyevent(rustyline::KeyCode::Insert, None),
|
||||
KeyEvent::Left => convert_to_rl_keyevent(rustyline::KeyCode::Left, None),
|
||||
KeyEvent::Meta(c) => rustyline::KeyEvent::new(c, Modifiers::NONE),
|
||||
KeyEvent::Null => convert_to_rl_keyevent(rustyline::KeyCode::Null, None),
|
||||
KeyEvent::PageDown => convert_to_rl_keyevent(rustyline::KeyCode::PageDown, None),
|
||||
KeyEvent::PageUp => convert_to_rl_keyevent(rustyline::KeyCode::PageUp, None),
|
||||
KeyEvent::Right => convert_to_rl_keyevent(rustyline::KeyCode::Right, None),
|
||||
KeyEvent::ShiftDown => {
|
||||
convert_to_rl_keyevent(rustyline::KeyCode::Down, Some(Modifiers::SHIFT))
|
||||
}
|
||||
KeyEvent::ShiftLeft => {
|
||||
convert_to_rl_keyevent(rustyline::KeyCode::Left, Some(Modifiers::SHIFT))
|
||||
}
|
||||
KeyEvent::ShiftRight => {
|
||||
convert_to_rl_keyevent(rustyline::KeyCode::Right, Some(Modifiers::SHIFT))
|
||||
}
|
||||
KeyEvent::ShiftUp => convert_to_rl_keyevent(rustyline::KeyCode::Up, Some(Modifiers::SHIFT)),
|
||||
KeyEvent::Tab => convert_to_rl_keyevent(rustyline::KeyCode::Tab, None),
|
||||
KeyEvent::Up => convert_to_rl_keyevent(rustyline::KeyCode::Up, None),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_to_rl_keyevent(key_event: KeyCode, modifier: Option<Modifiers>) -> rustyline::KeyEvent {
|
||||
rustyline::KeyEvent {
|
||||
0: key_event,
|
||||
1: modifier.unwrap_or(Modifiers::NONE),
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,7 +123,9 @@ fn convert_cmd(cmd: Cmd) -> rustyline::Cmd {
|
||||
match cmd {
|
||||
Cmd::Abort => rustyline::Cmd::Abort,
|
||||
Cmd::AcceptLine => rustyline::Cmd::AcceptLine,
|
||||
Cmd::AcceptOrInsertLine => rustyline::Cmd::AcceptOrInsertLine,
|
||||
Cmd::AcceptOrInsertLine => rustyline::Cmd::AcceptOrInsertLine {
|
||||
accept_in_the_middle: false,
|
||||
},
|
||||
Cmd::BeginningOfHistory => rustyline::Cmd::BeginningOfHistory,
|
||||
Cmd::CapitalizeWord => rustyline::Cmd::CapitalizeWord,
|
||||
Cmd::ClearScreen => rustyline::Cmd::ClearScreen,
|
||||
@ -140,18 +168,18 @@ fn convert_cmd(cmd: Cmd) -> rustyline::Cmd {
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_keybinding(keybinding: Keybinding) -> (rustyline::KeyPress, rustyline::Cmd) {
|
||||
fn convert_keybinding(keybinding: Keybinding) -> (rustyline::KeyEvent, rustyline::Cmd) {
|
||||
(
|
||||
convert_keypress(keybinding.key),
|
||||
convert_keyevent(keybinding.key),
|
||||
convert_cmd(keybinding.binding),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum KeyPress {
|
||||
pub enum KeyEvent {
|
||||
/// Unsupported escape sequence (on unix platform)
|
||||
UnknownEscSeq,
|
||||
/// ⌫ or `KeyPress::Ctrl('H')`
|
||||
/// ⌫ or `KeyEvent::Ctrl('H')`
|
||||
Backspace,
|
||||
/// ⇤ (usually Shift-Tab)
|
||||
BackTab,
|
||||
@ -177,9 +205,9 @@ pub enum KeyPress {
|
||||
Down,
|
||||
/// ⇲
|
||||
End,
|
||||
/// ↵ or `KeyPress::Ctrl('M')`
|
||||
/// ↵ or `KeyEvent::Ctrl('M')`
|
||||
Enter,
|
||||
/// Escape or `KeyPress::Ctrl('[')`
|
||||
/// Escape or `KeyEvent::Ctrl('[')`
|
||||
Esc,
|
||||
/// Function key
|
||||
F(u8),
|
||||
@ -191,7 +219,7 @@ pub enum KeyPress {
|
||||
Left,
|
||||
/// Escape-char or Alt-char
|
||||
Meta(char),
|
||||
/// `KeyPress::Char('\0')`
|
||||
/// `KeyEvent::Char('\0')`
|
||||
Null,
|
||||
/// ⇟
|
||||
PageDown,
|
||||
@ -207,7 +235,7 @@ pub enum KeyPress {
|
||||
ShiftRight,
|
||||
/// Shift-↑
|
||||
ShiftUp,
|
||||
/// ⇥ or `KeyPress::Ctrl('I')`
|
||||
/// ⇥ or `KeyEvent::Ctrl('I')`
|
||||
Tab,
|
||||
/// ↑ arrow key
|
||||
Up,
|
||||
@ -399,7 +427,7 @@ pub type RepeatCount = usize;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Keybinding {
|
||||
key: KeyPress,
|
||||
key: KeyEvent,
|
||||
binding: Cmd,
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ pub mod types;
|
||||
pub use crate::cli::cli;
|
||||
|
||||
pub use crate::cli::{parse_and_eval, register_plugins, run_script_file};
|
||||
pub use crate::cli::{NuScript, Options};
|
||||
|
||||
pub use crate::env::environment_syncer::EnvironmentSyncer;
|
||||
pub use nu_command::commands::default_context::create_default_context;
|
||||
|
@ -5,7 +5,10 @@ use std::error::Error;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use nu_command::script::LineResult;
|
||||
use nu_engine::script::LineResult;
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
use crate::keybinding::{convert_keyevent, KeyEvent};
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
use crate::shell::Helper;
|
||||
@ -16,7 +19,7 @@ use rustyline::{
|
||||
config::Configurer,
|
||||
config::{ColorMode, CompletionType, Config},
|
||||
error::ReadlineError,
|
||||
At, Cmd, Editor, KeyPress, Movement, Word,
|
||||
At, Cmd, Editor, Movement, Word,
|
||||
};
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
@ -40,22 +43,27 @@ pub fn default_rustyline_editor_configuration() -> Editor<Helper> {
|
||||
#[cfg(not(windows))]
|
||||
const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::List;
|
||||
|
||||
let config = Config::builder().color_mode(ColorMode::Forced).build();
|
||||
let config = Config::builder()
|
||||
.check_cursor_position(true)
|
||||
.color_mode(ColorMode::Forced)
|
||||
.build();
|
||||
let mut rl: Editor<_> = Editor::with_config(config);
|
||||
|
||||
// add key bindings to move over a whole word with Ctrl+ArrowLeft and Ctrl+ArrowRight
|
||||
rl.bind_sequence(
|
||||
KeyPress::ControlLeft,
|
||||
convert_keyevent(KeyEvent::ControlLeft),
|
||||
Cmd::Move(Movement::BackwardWord(1, Word::Vi)),
|
||||
);
|
||||
rl.bind_sequence(
|
||||
KeyPress::ControlRight,
|
||||
convert_keyevent(KeyEvent::ControlRight),
|
||||
Cmd::Move(Movement::ForwardWord(1, At::AfterEnd, Word::Vi)),
|
||||
);
|
||||
|
||||
// workaround for multiline-paste hang in rustyline (see https://github.com/kkawakam/rustyline/issues/202)
|
||||
rl.bind_sequence(KeyPress::BracketedPasteStart, rustyline::Cmd::Noop);
|
||||
|
||||
rl.bind_sequence(
|
||||
convert_keyevent(KeyEvent::BracketedPasteStart),
|
||||
rustyline::Cmd::Noop,
|
||||
);
|
||||
// Let's set the defaults up front and then override them later if the user indicates
|
||||
// defaults taken from here https://github.com/kkawakam/rustyline/blob/2fe886c9576c1ea13ca0e5808053ad491a6fe049/src/config.rs#L150-L167
|
||||
rl.set_max_history_size(100);
|
||||
|
@ -57,6 +57,7 @@ impl rustyline::completion::Completer for Helper {
|
||||
}
|
||||
|
||||
impl rustyline::hint::Hinter for Helper {
|
||||
type Hint = String;
|
||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
self.hinter.as_ref().and_then(|h| h.hint(line, pos, &ctx))
|
||||
}
|
||||
@ -148,7 +149,6 @@ impl rustyline::Helper for Helper {}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nu_engine::basic_evaluation_context;
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::line_buffer::LineBuffer;
|
||||
|
||||
@ -162,7 +162,7 @@ mod tests {
|
||||
buffer.insert_str(0, text);
|
||||
buffer.set_pos(text.len() - 1);
|
||||
|
||||
let helper = Helper::new(basic_evaluation_context().unwrap(), None);
|
||||
let helper = Helper::new(EvaluationContext::basic().unwrap(), None);
|
||||
|
||||
helper.update(&mut buffer, "cd ".len(), &replacement);
|
||||
|
||||
@ -182,7 +182,7 @@ mod tests {
|
||||
buffer.insert_str(0, text);
|
||||
buffer.set_pos(text.len() - 30);
|
||||
|
||||
let helper = Helper::new(basic_evaluation_context().unwrap(), None);
|
||||
let helper = Helper::new(EvaluationContext::basic().unwrap(), None);
|
||||
|
||||
helper.update(&mut buffer, "cd ".len(), &replacement);
|
||||
|
||||
|
@ -5,25 +5,25 @@ description = "CLI for nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-command"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
nu-data = { version = "0.28.0", path = "../nu-data" }
|
||||
nu-engine = { version = "0.28.0", path = "../nu-engine" }
|
||||
nu-errors = { version = "0.28.0", path = "../nu-errors" }
|
||||
nu-json = { version = "0.28.0", path = "../nu-json" }
|
||||
nu-parser = { version = "0.28.0", path = "../nu-parser" }
|
||||
nu-plugin = { version = "0.28.0", path = "../nu-plugin" }
|
||||
nu-protocol = { version = "0.28.0", path = "../nu-protocol" }
|
||||
nu-source = { version = "0.28.0", path = "../nu-source" }
|
||||
nu-stream = { version = "0.28.0", path = "../nu-stream" }
|
||||
nu-table = { version = "0.28.0", path = "../nu-table" }
|
||||
nu-test-support = { version = "0.28.0", path = "../nu-test-support" }
|
||||
nu-value-ext = { version = "0.28.0", path = "../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.28.0", path = "../nu-ansi-term" }
|
||||
nu-data = { version = "0.29.0", path = "../nu-data" }
|
||||
nu-engine = { version = "0.29.0", path = "../nu-engine" }
|
||||
nu-errors = { version = "0.29.0", path = "../nu-errors" }
|
||||
nu-json = { version = "0.29.0", path = "../nu-json" }
|
||||
nu-parser = { version = "0.29.0", path = "../nu-parser" }
|
||||
nu-plugin = { version = "0.29.0", path = "../nu-plugin" }
|
||||
nu-protocol = { version = "0.29.0", path = "../nu-protocol" }
|
||||
nu-source = { version = "0.29.0", path = "../nu-source" }
|
||||
nu-stream = { version = "0.29.0", path = "../nu-stream" }
|
||||
nu-table = { version = "0.29.0", path = "../nu-table" }
|
||||
nu-test-support = { version = "0.29.0", path = "../nu-test-support" }
|
||||
nu-value-ext = { version = "0.29.0", path = "../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.29.0", path = "../nu-ansi-term" }
|
||||
|
||||
Inflector = "0.11"
|
||||
arboard = { version = "1.1.0", optional = true }
|
||||
@ -62,6 +62,7 @@ indexmap = { version = "1.6.1", features = ["serde-1"] }
|
||||
itertools = "0.10.0"
|
||||
lazy_static = "1.*"
|
||||
log = "0.4.14"
|
||||
md5 = "0.7.0"
|
||||
meval = "0.2.0"
|
||||
minus = { version = "3.3.0", optional = true, features = ["async_std_lib", "search"] }
|
||||
num-bigint = { version = "0.3.1", features = ["serde"] }
|
||||
@ -78,7 +79,7 @@ rayon = "1.5.0"
|
||||
regex = "1.4.3"
|
||||
roxmltree = "0.14.0"
|
||||
rust-embed = "5.9.0"
|
||||
rustyline = { version = "7.1.0", optional = true }
|
||||
rustyline = { version = "8.0.0", optional = true }
|
||||
serde = { version = "1.0.123", features = ["derive"] }
|
||||
serde_bytes = "0.11.5"
|
||||
serde_ini = "0.2.0"
|
||||
@ -124,6 +125,7 @@ shadow-rs = "0.5"
|
||||
[dev-dependencies]
|
||||
quickcheck = "1.0.3"
|
||||
quickcheck_macros = "1.0.0"
|
||||
hamcrest2 = "0.3.0"
|
||||
|
||||
[features]
|
||||
clipboard-cli = ["arboard"]
|
||||
|
@ -20,11 +20,9 @@ pub(crate) mod chart;
|
||||
pub(crate) mod classified;
|
||||
#[cfg(feature = "clipboard-cli")]
|
||||
pub(crate) mod clip;
|
||||
pub mod command;
|
||||
pub(crate) mod compact;
|
||||
pub(crate) mod config;
|
||||
pub(crate) mod constants;
|
||||
pub(crate) mod count;
|
||||
pub(crate) mod cp;
|
||||
pub(crate) mod date;
|
||||
pub(crate) mod debug;
|
||||
@ -73,6 +71,7 @@ pub(crate) mod insert;
|
||||
pub(crate) mod into_int;
|
||||
pub(crate) mod keep;
|
||||
pub(crate) mod last;
|
||||
pub(crate) mod length;
|
||||
pub(crate) mod let_;
|
||||
pub(crate) mod let_env;
|
||||
pub(crate) mod lines;
|
||||
@ -153,9 +152,8 @@ pub(crate) use char_::Char;
|
||||
pub(crate) use chart::Chart;
|
||||
pub(crate) use compact::Compact;
|
||||
pub(crate) use config::{
|
||||
Config, ConfigClear, ConfigGet, ConfigLoad, ConfigPath, ConfigRemove, ConfigSet, ConfigSetInto,
|
||||
Config, ConfigClear, ConfigGet, ConfigPath, ConfigRemove, ConfigSet, ConfigSetInto,
|
||||
};
|
||||
pub(crate) use count::Count;
|
||||
pub(crate) use cp::Cpy;
|
||||
pub(crate) use date::{Date, DateFormat, DateListTimeZone, DateNow, DateToTable, DateToTimeZone};
|
||||
pub(crate) use debug::Debug;
|
||||
@ -186,25 +184,25 @@ pub(crate) use first::First;
|
||||
pub(crate) use flatten::Command as Flatten;
|
||||
pub(crate) use format::{FileSize, Format};
|
||||
pub(crate) use from::From;
|
||||
pub(crate) use from_csv::FromCSV;
|
||||
pub(crate) use from_eml::FromEML;
|
||||
pub(crate) use from_csv::FromCsv;
|
||||
pub(crate) use from_eml::FromEml;
|
||||
pub(crate) use from_ics::FromIcs;
|
||||
pub(crate) use from_ini::FromINI;
|
||||
pub(crate) use from_json::FromJSON;
|
||||
pub(crate) use from_ods::FromODS;
|
||||
pub(crate) use from_ssv::FromSSV;
|
||||
pub(crate) use from_toml::FromTOML;
|
||||
pub(crate) use from_tsv::FromTSV;
|
||||
pub(crate) use from_url::FromURL;
|
||||
pub(crate) use from_ini::FromIni;
|
||||
pub(crate) use from_json::FromJson;
|
||||
pub(crate) use from_ods::FromOds;
|
||||
pub(crate) use from_ssv::FromSsv;
|
||||
pub(crate) use from_toml::FromToml;
|
||||
pub(crate) use from_tsv::FromTsv;
|
||||
pub(crate) use from_url::FromUrl;
|
||||
pub(crate) use from_vcf::FromVcf;
|
||||
pub(crate) use from_xlsx::FromXLSX;
|
||||
pub(crate) use from_xml::FromXML;
|
||||
pub(crate) use from_yaml::FromYAML;
|
||||
pub(crate) use from_yaml::FromYML;
|
||||
pub(crate) use from_xlsx::FromXlsx;
|
||||
pub(crate) use from_xml::FromXml;
|
||||
pub(crate) use from_yaml::FromYaml;
|
||||
pub(crate) use from_yaml::FromYml;
|
||||
pub(crate) use get::Command as Get;
|
||||
pub(crate) use group_by::Command as GroupBy;
|
||||
pub(crate) use group_by_date::GroupByDate;
|
||||
pub(crate) use hash_::{Hash, HashBase64};
|
||||
pub(crate) use hash_::{Hash, HashBase64, HashMd5};
|
||||
pub(crate) use headers::Headers;
|
||||
pub(crate) use help::Help;
|
||||
pub(crate) use histogram::Histogram;
|
||||
@ -213,6 +211,7 @@ pub(crate) use insert::Command as Insert;
|
||||
pub(crate) use into_int::IntoInt;
|
||||
pub(crate) use keep::{Keep, KeepUntil, KeepWhile};
|
||||
pub(crate) use last::Last;
|
||||
pub(crate) use length::Length;
|
||||
pub(crate) use let_::Let;
|
||||
pub(crate) use let_env::LetEnv;
|
||||
pub(crate) use lines::Lines;
|
||||
@ -273,15 +272,15 @@ pub(crate) use table::Table;
|
||||
pub(crate) use tags::Tags;
|
||||
pub(crate) use termsize::TermSize;
|
||||
pub(crate) use to::To;
|
||||
pub(crate) use to_csv::ToCSV;
|
||||
pub(crate) use to_html::ToHTML;
|
||||
pub(crate) use to_json::ToJSON;
|
||||
pub(crate) use to_csv::ToCsv;
|
||||
pub(crate) use to_html::ToHtml;
|
||||
pub(crate) use to_json::ToJson;
|
||||
pub(crate) use to_md::Command as ToMarkdown;
|
||||
pub(crate) use to_toml::ToTOML;
|
||||
pub(crate) use to_tsv::ToTSV;
|
||||
pub(crate) use to_url::ToURL;
|
||||
pub(crate) use to_xml::ToXML;
|
||||
pub(crate) use to_yaml::ToYAML;
|
||||
pub(crate) use to_toml::ToToml;
|
||||
pub(crate) use to_tsv::ToTsv;
|
||||
pub(crate) use to_url::ToUrl;
|
||||
pub(crate) use to_xml::ToXml;
|
||||
pub(crate) use to_yaml::ToYaml;
|
||||
pub(crate) use touch::Touch;
|
||||
pub(crate) use uniq::Uniq;
|
||||
pub(crate) use url_::{UrlCommand, UrlHost, UrlPath, UrlQuery, UrlScheme};
|
||||
|
@ -9,6 +9,7 @@ pub struct Char;
|
||||
#[derive(Deserialize)]
|
||||
struct CharArgs {
|
||||
name: Tagged<String>,
|
||||
rest: Vec<Tagged<String>>,
|
||||
unicode: bool,
|
||||
}
|
||||
|
||||
@ -25,6 +26,7 @@ impl WholeStreamCommand for Char {
|
||||
SyntaxShape::Any,
|
||||
"the name of the character to output",
|
||||
)
|
||||
.rest(SyntaxShape::String, "multiple unicode bytes")
|
||||
.switch("unicode", "unicode string i.e. 1f378", Some('u'))
|
||||
}
|
||||
|
||||
@ -53,24 +55,60 @@ impl WholeStreamCommand for Char {
|
||||
example: r#"char -u 1f378"#,
|
||||
result: Some(vec![Value::from("\u{1f378}")]),
|
||||
},
|
||||
Example {
|
||||
description: "Output multi-byte unicode character",
|
||||
example: r#"char -u 1F468 200D 1F466 200D 1F466"#,
|
||||
result: Some(vec![Value::from(
|
||||
"\u{1F468}\u{200D}\u{1F466}\u{200D}\u{1F466}",
|
||||
)]),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let (CharArgs { name, unicode }, _) = args.process().await?;
|
||||
let (
|
||||
CharArgs {
|
||||
name,
|
||||
rest,
|
||||
unicode,
|
||||
},
|
||||
_,
|
||||
) = args.process().await?;
|
||||
|
||||
if unicode {
|
||||
let decoded_char = string_to_unicode_char(&name.item);
|
||||
if let Some(output) = decoded_char {
|
||||
if !rest.is_empty() {
|
||||
// Setup a new buffer to put all the unicode bytes in
|
||||
let mut multi_byte = String::new();
|
||||
// Get the first byte
|
||||
let decoded_char = string_to_unicode_char(&name.item, &name.tag);
|
||||
match decoded_char {
|
||||
Ok(ch) => multi_byte.push(ch),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
// Get the rest of the bytes
|
||||
for byte_part in rest {
|
||||
let decoded_char = string_to_unicode_char(&byte_part, &byte_part.tag);
|
||||
match decoded_char {
|
||||
Ok(ch) => multi_byte.push(ch),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(output).into_value(name.tag()),
|
||||
UntaggedValue::string(multi_byte).into_value(name.tag),
|
||||
)))
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"error decoding unicode character",
|
||||
"error decoding unicode character",
|
||||
name.tag(),
|
||||
))
|
||||
let decoded_char = string_to_unicode_char(&name.item, &name.tag);
|
||||
if let Ok(ch) = decoded_char {
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(ch).into_value(name.tag()),
|
||||
)))
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"error decoding unicode character",
|
||||
"error decoding unicode character",
|
||||
name.tag(),
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let special_character = str_to_character(&name.item);
|
||||
@ -89,10 +127,20 @@ impl WholeStreamCommand for Char {
|
||||
}
|
||||
}
|
||||
|
||||
fn string_to_unicode_char(s: &str) -> Option<char> {
|
||||
u32::from_str_radix(s, 16)
|
||||
fn string_to_unicode_char(s: &str, t: &Tag) -> Result<char, ShellError> {
|
||||
let decoded_char = u32::from_str_radix(s, 16)
|
||||
.ok()
|
||||
.and_then(std::char::from_u32)
|
||||
.and_then(std::char::from_u32);
|
||||
|
||||
if let Some(ch) = decoded_char {
|
||||
Ok(ch)
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"error decoding unicode character",
|
||||
"error decoding unicode character",
|
||||
t,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn str_to_character(s: &str) -> Option<String> {
|
||||
|
@ -28,7 +28,7 @@ pub(crate) async fn run_external_command(
|
||||
) -> Result<InputStream, ShellError> {
|
||||
trace!(target: "nu::run::external", "-> {}", command.name);
|
||||
|
||||
if !did_find_command(&command.name) {
|
||||
if !context.host.lock().is_external_cmd(&command.name) {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Command not found",
|
||||
"command not found",
|
||||
@ -443,35 +443,6 @@ fn spawn(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn did_find_command(#[allow(unused)] name: &str) -> bool {
|
||||
#[cfg(not(feature = "which"))]
|
||||
{
|
||||
// we can't perform this check, so just assume it can be found
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "which", unix))]
|
||||
{
|
||||
which::which(name).is_ok()
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "which", windows))]
|
||||
{
|
||||
if which::which(name).is_ok() {
|
||||
true
|
||||
} else {
|
||||
// Reference: https://ss64.com/nt/syntax-internal.html
|
||||
let cmd_builtins = [
|
||||
"assoc", "break", "color", "copy", "date", "del", "dir", "dpath", "echo", "erase",
|
||||
"for", "ftype", "md", "mkdir", "mklink", "move", "path", "ren", "rename", "rd",
|
||||
"rmdir", "start", "time", "title", "type", "ver", "verify", "vol",
|
||||
];
|
||||
|
||||
cmd_builtins.contains(&name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_tilde<SI: ?Sized, P, HD>(input: &SI, home_dir: HD) -> std::borrow::Cow<str>
|
||||
where
|
||||
SI: AsRef<str>,
|
||||
@ -538,7 +509,7 @@ mod tests {
|
||||
#[cfg(feature = "which")]
|
||||
use futures::executor::block_on;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_engine::basic_evaluation_context;
|
||||
use nu_engine::EvaluationContext;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_errors::ShellError;
|
||||
#[cfg(feature = "which")]
|
||||
@ -563,7 +534,7 @@ mod tests {
|
||||
|
||||
let input = InputStream::empty();
|
||||
let mut ctx =
|
||||
basic_evaluation_context().expect("There was a problem creating a basic context.");
|
||||
EvaluationContext::basic().expect("There was a problem creating a basic context.");
|
||||
|
||||
assert!(
|
||||
run_external_command(cmd, &mut ctx, input, ExternalRedirection::Stdout)
|
||||
@ -577,7 +548,7 @@ mod tests {
|
||||
// async fn failure_run() -> Result<(), ShellError> {
|
||||
// let cmd = ExternalBuilder::for_name("fail").build();
|
||||
|
||||
// let mut ctx = crate::cli::basic_evaluation_context().expect("There was a problem creating a basic context.");
|
||||
// let mut ctx = crate::cli::EvaluationContext::basic().expect("There was a problem creating a basic context.");
|
||||
// let stream = run_external_command(cmd, &mut ctx, None, false)
|
||||
// .await?
|
||||
// .expect("There was a problem running the external command.");
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
@ -35,13 +35,19 @@ impl WholeStreamCommand for SubCommand {
|
||||
pub async fn clear(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
|
||||
// NOTE: None because we are not loading a new config file, we just want to read from the
|
||||
// existing config
|
||||
let mut result = nu_data::config::read(name_span, &None)?;
|
||||
let path = match args.scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
};
|
||||
|
||||
let mut result = nu_data::config::read(name_span, &path)?;
|
||||
|
||||
result.clear();
|
||||
|
||||
config::write(&result, &None)?;
|
||||
config::write(&result, &path)?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(args.call_info.name_tag),
|
||||
|
@ -2,7 +2,7 @@ use crate::prelude::*;
|
||||
use nu_engine::CommandArgs;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
use nu_stream::OutputStream;
|
||||
|
||||
pub struct Command;
|
||||
@ -22,9 +22,16 @@ impl WholeStreamCommand for Command {
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let name = args.call_info.name_tag;
|
||||
let result = nu_data::config::read(name_span, &None)?;
|
||||
let name = args.call_info.name_tag.clone();
|
||||
|
||||
let path = match args.scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
};
|
||||
let result = nu_data::config::read(&name, &path)?;
|
||||
|
||||
Ok(futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
|
@ -1,13 +1,15 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{
|
||||
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetArgs {
|
||||
path: ColumnPath,
|
||||
pub struct Arguments {
|
||||
column_path: ColumnPath,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -42,14 +44,21 @@ impl WholeStreamCommand for SubCommand {
|
||||
}
|
||||
|
||||
pub async fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
let (GetArgs { path }, _) = args.process().await?;
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let scope = args.scope.clone();
|
||||
let (Arguments { column_path }, _) = args.process().await?;
|
||||
|
||||
// NOTE: None because we are not loading a new config file, we just want to read from the
|
||||
// existing config
|
||||
let result = UntaggedValue::row(nu_data::config::read(&name_tag, &None)?).into_value(&name_tag);
|
||||
let path = match scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
};
|
||||
|
||||
let value = crate::commands::get::get_column_path(&path, &result)?;
|
||||
let result = UntaggedValue::row(nu_data::config::read(&name, &path)?).into_value(&name);
|
||||
|
||||
let value = crate::commands::get::get_column_path(&column_path, &result)?;
|
||||
|
||||
Ok(match value {
|
||||
Value {
|
||||
|
@ -1,51 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct LoadArgs {
|
||||
load: Tagged<PathBuf>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"config load"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config load").required(
|
||||
"load",
|
||||
SyntaxShape::FilePath,
|
||||
"Path to load the config from",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Loads the config from the path given"
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
set(args).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let (LoadArgs { load }, _) = args.process().await?;
|
||||
|
||||
let configuration = load.item().clone();
|
||||
|
||||
let result = nu_data::config::read(name_span, &Some(configuration))?;
|
||||
|
||||
Ok(futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
)])
|
||||
.to_output_stream())
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
pub mod clear;
|
||||
pub mod command;
|
||||
pub mod get;
|
||||
pub mod load;
|
||||
pub mod path;
|
||||
pub mod remove;
|
||||
pub mod set;
|
||||
@ -10,7 +9,6 @@ pub mod set_into;
|
||||
pub use clear::SubCommand as ConfigClear;
|
||||
pub use command::Command as Config;
|
||||
pub use get::SubCommand as ConfigGet;
|
||||
pub use load::SubCommand as ConfigLoad;
|
||||
pub use path::SubCommand as ConfigPath;
|
||||
pub use remove::SubCommand as ConfigRemove;
|
||||
pub use set::SubCommand as ConfigSet;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
@ -33,9 +33,18 @@ impl WholeStreamCommand for SubCommand {
|
||||
}
|
||||
|
||||
pub async fn path(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let path = config::default_path()?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Primitive(Primitive::FilePath(path)).into_value(args.call_info.name_tag),
|
||||
match args.scope.get_var("config-path") {
|
||||
Some(
|
||||
path
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(_)),
|
||||
..
|
||||
},
|
||||
) => path,
|
||||
_ => UntaggedValue::Primitive(Primitive::FilePath(nu_data::config::default_path()?))
|
||||
.into_value(args.call_info.name_tag),
|
||||
},
|
||||
)))
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct RemoveArgs {
|
||||
pub struct Arguments {
|
||||
remove: Tagged<String>,
|
||||
}
|
||||
|
||||
@ -44,15 +44,24 @@ impl WholeStreamCommand for SubCommand {
|
||||
|
||||
pub async fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let (RemoveArgs { remove }, _) = args.process().await?;
|
||||
let scope = args.scope.clone();
|
||||
let (Arguments { remove }, _) = args.process().await?;
|
||||
|
||||
let mut result = nu_data::config::read(name_span, &None)?;
|
||||
let path = match scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
};
|
||||
|
||||
let mut result = nu_data::config::read(name_span, &path)?;
|
||||
|
||||
let key = remove.to_string();
|
||||
|
||||
if result.contains_key(&key) {
|
||||
result.swap_remove(&key);
|
||||
config::write(&result, &None)?;
|
||||
config::write(&result, &path)?;
|
||||
Ok(futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(remove.tag()),
|
||||
)])
|
||||
|
@ -1,13 +1,15 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{
|
||||
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetArgs {
|
||||
path: ColumnPath,
|
||||
pub struct Arguments {
|
||||
column_path: ColumnPath,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
@ -58,13 +60,26 @@ impl WholeStreamCommand for SubCommand {
|
||||
}
|
||||
|
||||
pub async fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
let (SetArgs { path, mut value }, _) = args.process().await?;
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let scope = args.scope.clone();
|
||||
let (
|
||||
Arguments {
|
||||
column_path,
|
||||
mut value,
|
||||
},
|
||||
_,
|
||||
) = args.process().await?;
|
||||
|
||||
// NOTE: None because we are not loading a new config file, we just want to read from the
|
||||
// existing config
|
||||
let raw_entries = nu_data::config::read(&name_tag, &None)?;
|
||||
let configuration = UntaggedValue::row(raw_entries).into_value(&name_tag);
|
||||
let path = match scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
};
|
||||
|
||||
let raw_entries = nu_data::config::read(&name, &path)?;
|
||||
let configuration = UntaggedValue::row(raw_entries).into_value(&name);
|
||||
|
||||
if let UntaggedValue::Table(rows) = &value.value {
|
||||
if rows.len() == 1 && rows[0].is_row() {
|
||||
@ -72,15 +87,15 @@ pub async fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
}
|
||||
}
|
||||
|
||||
match configuration.forgiving_insert_data_at_column_path(&path, value) {
|
||||
match configuration.forgiving_insert_data_at_column_path(&column_path, value) {
|
||||
Ok(Value {
|
||||
value: UntaggedValue::Row(changes),
|
||||
..
|
||||
}) => {
|
||||
config::write(&changes.entries, &None)?;
|
||||
config::write(&changes.entries, &path)?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(changes).into_value(name_tag),
|
||||
UntaggedValue::Row(changes).into_value(name),
|
||||
)))
|
||||
}
|
||||
Ok(_) => Ok(OutputStream::empty()),
|
||||
|
@ -1,13 +1,13 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetIntoArgs {
|
||||
pub struct Arguments {
|
||||
set_into: Tagged<String>,
|
||||
}
|
||||
|
||||
@ -43,17 +43,19 @@ impl WholeStreamCommand for SubCommand {
|
||||
}
|
||||
|
||||
pub async fn set_into(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let scope = args.scope.clone();
|
||||
let (Arguments { set_into: v }, input) = args.process().await?;
|
||||
|
||||
let (SetIntoArgs { set_into: v }, input) = args.process().await?;
|
||||
let path = match scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
};
|
||||
|
||||
// NOTE: None because we are not loading a new config file, we just want to read from the
|
||||
// existing config
|
||||
let mut result = nu_data::config::read(name_span, &None)?;
|
||||
|
||||
// In the original code, this is set to `Some` if the `load flag is set`
|
||||
let configuration = None;
|
||||
let mut result = nu_data::config::read(&name, &path)?;
|
||||
|
||||
let rows: Vec<Value> = input.collect().await;
|
||||
let key = v.to_string();
|
||||
@ -70,7 +72,7 @@ pub async fn set_into(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
result.insert(key, value.clone());
|
||||
|
||||
config::write(&result, &configuration)?;
|
||||
config::write(&result, &path)?;
|
||||
|
||||
OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
@ -81,7 +83,7 @@ pub async fn set_into(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
result.insert(key, value);
|
||||
|
||||
config::write(&result, &configuration)?;
|
||||
config::write(&result, &path)?;
|
||||
|
||||
OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
|
@ -27,10 +27,11 @@ impl WholeStreamCommand for Date {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert a date to a given time zone.
|
||||
|
||||
Use `date list-timezone` to list all supported time zones.
|
||||
"
|
||||
"Convert a date to a given time zone."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
"Use 'date list-timezone' to list all supported time zones."
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -1,10 +1,9 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::basic_evaluation_context;
|
||||
use nu_engine::whole_stream_command;
|
||||
use nu_engine::EvaluationContext;
|
||||
use std::error::Error;
|
||||
|
||||
pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Box<dyn Error>> {
|
||||
let context = basic_evaluation_context()?;
|
||||
let context = EvaluationContext::basic()?;
|
||||
|
||||
{
|
||||
use crate::commands::*;
|
||||
@ -29,7 +28,6 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
whole_stream_command(ConfigSet),
|
||||
whole_stream_command(ConfigSetInto),
|
||||
whole_stream_command(ConfigClear),
|
||||
whole_stream_command(ConfigLoad),
|
||||
whole_stream_command(ConfigRemove),
|
||||
whole_stream_command(ConfigPath),
|
||||
whole_stream_command(Help),
|
||||
@ -57,7 +55,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
whole_stream_command(Sleep),
|
||||
// Statistics
|
||||
whole_stream_command(Size),
|
||||
whole_stream_command(Count),
|
||||
whole_stream_command(Length),
|
||||
whole_stream_command(Benchmark),
|
||||
// Metadata
|
||||
whole_stream_command(Tags),
|
||||
@ -75,6 +73,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
// Text manipulation
|
||||
whole_stream_command(Hash),
|
||||
whole_stream_command(HashBase64),
|
||||
whole_stream_command(HashMd5),
|
||||
whole_stream_command(Split),
|
||||
whole_stream_command(SplitColumn),
|
||||
whole_stream_command(SplitRow),
|
||||
@ -190,30 +189,30 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
whole_stream_command(MathCeil),
|
||||
// File format output
|
||||
whole_stream_command(To),
|
||||
whole_stream_command(ToCSV),
|
||||
whole_stream_command(ToHTML),
|
||||
whole_stream_command(ToJSON),
|
||||
whole_stream_command(ToCsv),
|
||||
whole_stream_command(ToHtml),
|
||||
whole_stream_command(ToJson),
|
||||
whole_stream_command(ToMarkdown),
|
||||
whole_stream_command(ToTOML),
|
||||
whole_stream_command(ToTSV),
|
||||
whole_stream_command(ToURL),
|
||||
whole_stream_command(ToYAML),
|
||||
whole_stream_command(ToXML),
|
||||
whole_stream_command(ToToml),
|
||||
whole_stream_command(ToTsv),
|
||||
whole_stream_command(ToUrl),
|
||||
whole_stream_command(ToYaml),
|
||||
whole_stream_command(ToXml),
|
||||
// File format input
|
||||
whole_stream_command(From),
|
||||
whole_stream_command(FromCSV),
|
||||
whole_stream_command(FromEML),
|
||||
whole_stream_command(FromTSV),
|
||||
whole_stream_command(FromSSV),
|
||||
whole_stream_command(FromINI),
|
||||
whole_stream_command(FromJSON),
|
||||
whole_stream_command(FromODS),
|
||||
whole_stream_command(FromTOML),
|
||||
whole_stream_command(FromURL),
|
||||
whole_stream_command(FromXLSX),
|
||||
whole_stream_command(FromXML),
|
||||
whole_stream_command(FromYAML),
|
||||
whole_stream_command(FromYML),
|
||||
whole_stream_command(FromCsv),
|
||||
whole_stream_command(FromEml),
|
||||
whole_stream_command(FromTsv),
|
||||
whole_stream_command(FromSsv),
|
||||
whole_stream_command(FromIni),
|
||||
whole_stream_command(FromJson),
|
||||
whole_stream_command(FromOds),
|
||||
whole_stream_command(FromToml),
|
||||
whole_stream_command(FromUrl),
|
||||
whole_stream_command(FromXlsx),
|
||||
whole_stream_command(FromXml),
|
||||
whole_stream_command(FromYaml),
|
||||
whole_stream_command(FromYml),
|
||||
whole_stream_command(FromIcs),
|
||||
whole_stream_command(FromVcf),
|
||||
// "Private" commands (not intended to be accessed directly)
|
||||
|
@ -4,16 +4,16 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct FromCSV;
|
||||
pub struct FromCsv;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FromCSVArgs {
|
||||
pub struct FromCsvArgs {
|
||||
noheaders: bool,
|
||||
separator: Option<Value>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromCSV {
|
||||
impl WholeStreamCommand for FromCsv {
|
||||
fn name(&self) -> &str {
|
||||
"from csv"
|
||||
}
|
||||
@ -71,7 +71,7 @@ async fn from_csv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
|
||||
let (
|
||||
FromCSVArgs {
|
||||
FromCsvArgs {
|
||||
noheaders,
|
||||
separator,
|
||||
},
|
||||
@ -105,13 +105,13 @@ async fn from_csv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromCSV;
|
||||
use super::FromCsv;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromCSV {})
|
||||
test_examples(FromCsv {})
|
||||
}
|
||||
}
|
||||
|
@ -6,18 +6,18 @@ use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct FromEML;
|
||||
pub struct FromEml;
|
||||
|
||||
const DEFAULT_BODY_PREVIEW: usize = 50;
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
pub struct FromEMLArgs {
|
||||
pub struct FromEmlArgs {
|
||||
#[serde(rename(deserialize = "preview-body"))]
|
||||
preview_body: Option<Tagged<usize>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromEML {
|
||||
impl WholeStreamCommand for FromEml {
|
||||
fn name(&self) -> &str {
|
||||
"from eml"
|
||||
}
|
||||
@ -75,7 +75,7 @@ fn headerfieldvalue_to_value(tag: &Tag, value: &HeaderFieldValue) -> UntaggedVal
|
||||
|
||||
async fn from_eml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let (eml_args, input): (FromEMLArgs, _) = args.process().await?;
|
||||
let (eml_args, input): (FromEmlArgs, _) = args.process().await?;
|
||||
let value = input.collect_string(tag.clone()).await?;
|
||||
|
||||
let body_preview = eml_args
|
||||
@ -121,13 +121,13 @@ async fn from_eml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromEML;
|
||||
use super::FromEml;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromEML {})
|
||||
test_examples(FromEml {})
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, Signature, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct FromINI;
|
||||
pub struct FromIni;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromINI {
|
||||
impl WholeStreamCommand for FromIni {
|
||||
fn name(&self) -> &str {
|
||||
"from ini"
|
||||
}
|
||||
@ -86,13 +86,13 @@ async fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromINI;
|
||||
use super::FromIni;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromINI {})
|
||||
test_examples(FromIni {})
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,15 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue, Value};
|
||||
|
||||
pub struct FromJSON;
|
||||
pub struct FromJson;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FromJSONArgs {
|
||||
pub struct FromJsonArgs {
|
||||
objects: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromJSON {
|
||||
impl WholeStreamCommand for FromJson {
|
||||
fn name(&self) -> &str {
|
||||
"from json"
|
||||
}
|
||||
@ -71,7 +71,7 @@ pub fn from_json_string_to_value(s: String, tag: impl Into<Tag>) -> nu_json::Res
|
||||
async fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (FromJSONArgs { objects }, input) = args.process().await?;
|
||||
let (FromJsonArgs { objects }, input) = args.process().await?;
|
||||
let concat_string = input.collect_string(name_tag.clone()).await?;
|
||||
|
||||
let string_clone: Vec<_> = concat_string.item.lines().map(|x| x.to_string()).collect();
|
||||
@ -135,13 +135,13 @@ async fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromJSON;
|
||||
use super::FromJson;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromJSON {})
|
||||
test_examples(FromJson {})
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,15 @@ use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue};
|
||||
use std::io::Cursor;
|
||||
|
||||
pub struct FromODS;
|
||||
pub struct FromOds;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FromODSArgs {
|
||||
pub struct FromOdsArgs {
|
||||
noheaders: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromODS {
|
||||
impl WholeStreamCommand for FromOds {
|
||||
fn name(&self) -> &str {
|
||||
"from ods"
|
||||
}
|
||||
@ -41,7 +41,7 @@ async fn from_ods(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let span = tag.span;
|
||||
|
||||
let (
|
||||
FromODSArgs {
|
||||
FromOdsArgs {
|
||||
noheaders: _noheaders,
|
||||
},
|
||||
input,
|
||||
@ -93,13 +93,13 @@ async fn from_ods(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromODS;
|
||||
use super::FromOds;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromODS {})
|
||||
test_examples(FromOds {})
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ use nu_protocol::{
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct FromSSV;
|
||||
pub struct FromSsv;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FromSSVArgs {
|
||||
pub struct FromSsvArgs {
|
||||
noheaders: bool,
|
||||
#[serde(rename(deserialize = "aligned-columns"))]
|
||||
aligned_columns: bool,
|
||||
@ -21,7 +21,7 @@ const STRING_REPRESENTATION: &str = "from ssv";
|
||||
const DEFAULT_MINIMUM_SPACES: usize = 2;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromSSV {
|
||||
impl WholeStreamCommand for FromSsv {
|
||||
fn name(&self) -> &str {
|
||||
STRING_REPRESENTATION
|
||||
}
|
||||
@ -250,7 +250,7 @@ fn from_ssv_string_to_value(
|
||||
async fn from_ssv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let (
|
||||
FromSSVArgs {
|
||||
FromSsvArgs {
|
||||
noheaders,
|
||||
aligned_columns,
|
||||
minimum_spaces,
|
||||
@ -489,9 +489,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use super::FromSSV;
|
||||
use super::FromSsv;
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromSSV {})
|
||||
test_examples(FromSsv {})
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue, Value};
|
||||
|
||||
pub struct FromTOML;
|
||||
pub struct FromToml;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromTOML {
|
||||
impl WholeStreamCommand for FromToml {
|
||||
fn name(&self) -> &str {
|
||||
"from toml"
|
||||
}
|
||||
@ -92,13 +92,13 @@ pub async fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromTOML;
|
||||
use super::FromToml;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromTOML {})
|
||||
test_examples(FromToml {})
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,15 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::Signature;
|
||||
|
||||
pub struct FromTSV;
|
||||
pub struct FromTsv;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FromTSVArgs {
|
||||
pub struct FromTsvArgs {
|
||||
noheaders: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromTSV {
|
||||
impl WholeStreamCommand for FromTsv {
|
||||
fn name(&self) -> &str {
|
||||
"from tsv"
|
||||
}
|
||||
@ -36,20 +36,20 @@ impl WholeStreamCommand for FromTSV {
|
||||
|
||||
async fn from_tsv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let (FromTSVArgs { noheaders }, input) = args.process().await?;
|
||||
let (FromTsvArgs { noheaders }, input) = args.process().await?;
|
||||
|
||||
from_delimited_data(noheaders, '\t', "TSV", input, name).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromTSV;
|
||||
use super::FromTsv;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromTSV {})
|
||||
test_examples(FromTsv {})
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue};
|
||||
|
||||
pub struct FromURL;
|
||||
pub struct FromUrl;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromURL {
|
||||
impl WholeStreamCommand for FromUrl {
|
||||
fn name(&self) -> &str {
|
||||
"from url"
|
||||
}
|
||||
@ -55,13 +55,13 @@ async fn from_url(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromURL;
|
||||
use super::FromUrl;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromURL {})
|
||||
test_examples(FromUrl {})
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,15 @@ use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue};
|
||||
use std::io::Cursor;
|
||||
|
||||
pub struct FromXLSX;
|
||||
pub struct FromXlsx;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FromXLSXArgs {
|
||||
pub struct FromXlsxArgs {
|
||||
noheaders: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromXLSX {
|
||||
impl WholeStreamCommand for FromXlsx {
|
||||
fn name(&self) -> &str {
|
||||
"from xlsx"
|
||||
}
|
||||
@ -40,7 +40,7 @@ async fn from_xlsx(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let span = tag.span;
|
||||
let (
|
||||
FromXLSXArgs {
|
||||
FromXlsxArgs {
|
||||
noheaders: _noheaders,
|
||||
},
|
||||
input,
|
||||
@ -93,13 +93,13 @@ async fn from_xlsx(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromXLSX;
|
||||
use super::FromXlsx;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromXLSX {})
|
||||
test_examples(FromXlsx {})
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue, Value};
|
||||
|
||||
pub struct FromXML;
|
||||
pub struct FromXml;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromXML {
|
||||
impl WholeStreamCommand for FromXml {
|
||||
fn name(&self) -> &str {
|
||||
"from xml"
|
||||
}
|
||||
@ -298,9 +298,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use super::FromXML;
|
||||
use super::FromXml;
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromXML {})
|
||||
test_examples(FromXml {})
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, Signature, TaggedDictBuilder, UntaggedValue, Value};
|
||||
|
||||
pub struct FromYAML;
|
||||
pub struct FromYaml;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromYAML {
|
||||
impl WholeStreamCommand for FromYaml {
|
||||
fn name(&self) -> &str {
|
||||
"from yaml"
|
||||
}
|
||||
@ -24,10 +24,10 @@ impl WholeStreamCommand for FromYAML {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FromYML;
|
||||
pub struct FromYml;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromYML {
|
||||
impl WholeStreamCommand for FromYml {
|
||||
fn name(&self) -> &str {
|
||||
"from yml"
|
||||
}
|
||||
@ -169,7 +169,7 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromYAML {})
|
||||
test_examples(FromYaml {})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
133
crates/nu-command/src/commands/hash_/md5_.rs
Normal file
133
crates/nu-command/src/commands/hash_/md5_.rs
Normal file
@ -0,0 +1,133 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::ShellTypeName;
|
||||
use nu_protocol::{
|
||||
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Tag;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Arguments {
|
||||
pub rest: Vec<ColumnPath>,
|
||||
}
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"hash md5"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("hash md5").rest(
|
||||
SyntaxShape::ColumnPath,
|
||||
"optionally md5 encode data by column paths",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"md5 encode a value"
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
operate(args).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "md5 encode a string",
|
||||
example: "echo 'abcdefghijklmnopqrstuvwxyz' | hash md5",
|
||||
result: Some(vec![UntaggedValue::string(
|
||||
"c3fcd3d76192e4007dfb496cca67e13b",
|
||||
)
|
||||
.into_untagged_value()]),
|
||||
},
|
||||
Example {
|
||||
description: "md5 encode a file",
|
||||
example: "open ./nu_0_24_1_windows.zip | hash md5",
|
||||
result: Some(vec![UntaggedValue::string(
|
||||
"dcf30f2836a1a99fc55cf72e28272606",
|
||||
)
|
||||
.into_untagged_value()]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
async fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let (Arguments { rest }, input) = args.process().await?;
|
||||
|
||||
let column_paths: Vec<_> = rest;
|
||||
|
||||
Ok(input
|
||||
.map(move |v| {
|
||||
if column_paths.is_empty() {
|
||||
ReturnSuccess::value(action(&v, v.tag())?)
|
||||
} else {
|
||||
let mut ret = v;
|
||||
|
||||
for path in &column_paths {
|
||||
ret = ret.swap_data_by_column_path(
|
||||
path,
|
||||
Box::new(move |old| action(old, old.tag())),
|
||||
)?;
|
||||
}
|
||||
|
||||
ReturnSuccess::value(ret)
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
match &input.value {
|
||||
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||
let md5_digest = md5::compute(s.as_bytes());
|
||||
Ok(UntaggedValue::string(&format!("{:x}", md5_digest)).into_value(tag))
|
||||
}
|
||||
UntaggedValue::Primitive(Primitive::Binary(bytes)) => {
|
||||
let md5_digest = md5::compute(bytes);
|
||||
Ok(UntaggedValue::string(&format!("{:x}", md5_digest)).into_value(tag))
|
||||
}
|
||||
other => {
|
||||
let got = format!("got {}", other.type_name());
|
||||
Err(ShellError::labeled_error(
|
||||
"value is not supported for hashing as md5",
|
||||
got,
|
||||
tag.into().span,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::action;
|
||||
use nu_protocol::{Primitive, UntaggedValue};
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn md5_encode_string() {
|
||||
let word = string("abcdefghijklmnopqrstuvwxyz");
|
||||
let expected =
|
||||
UntaggedValue::string("c3fcd3d76192e4007dfb496cca67e13b").into_untagged_value();
|
||||
|
||||
let actual = action(&word, Tag::unknown()).unwrap();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn md5_encode_bytes() {
|
||||
let bytes = vec![0xC0, 0xFF, 0xEE];
|
||||
let binary = UntaggedValue::Primitive(Primitive::Binary(bytes)).into_untagged_value();
|
||||
let expected =
|
||||
UntaggedValue::string("5f80e231382769b0102b1164cf722d83").into_untagged_value();
|
||||
|
||||
let actual = action(&binary, Tag::unknown()).unwrap();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
mod base64_;
|
||||
mod command;
|
||||
mod md5_;
|
||||
|
||||
pub use base64_::SubCommand as HashBase64;
|
||||
pub use command::Command as Hash;
|
||||
pub use md5_::SubCommand as HashMd5;
|
||||
|
@ -29,7 +29,7 @@ impl WholeStreamCommand for Headers {
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Create headers for a raw string",
|
||||
description: "Create headers from a raw string",
|
||||
example: r#"echo "a b c|1 2 3" | split row "|" | split column " " | headers"#,
|
||||
result: None,
|
||||
},
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::prelude::*;
|
||||
use nu_data::config::{Conf, NuConfig};
|
||||
use nu_engine::history_path;
|
||||
use nu_data::config::{path::history as history_path, NuConfig};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
@ -34,7 +33,7 @@ impl WholeStreamCommand for History {
|
||||
}
|
||||
|
||||
async fn history(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let config: Box<dyn Conf> = Box::new(NuConfig::new());
|
||||
let config = NuConfig::new();
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let (Arguments { clear }, _) = args.process().await?;
|
||||
|
||||
|
@ -13,6 +13,7 @@ pub struct KillArgs {
|
||||
pub rest: Vec<Tagged<u64>>,
|
||||
pub force: Tagged<bool>,
|
||||
pub quiet: Tagged<bool>,
|
||||
pub signal: Option<Tagged<u32>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -22,7 +23,7 @@ impl WholeStreamCommand for Kill {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("kill")
|
||||
let signature = Signature::build("kill")
|
||||
.required(
|
||||
"pid",
|
||||
SyntaxShape::Int,
|
||||
@ -30,7 +31,18 @@ impl WholeStreamCommand for Kill {
|
||||
)
|
||||
.rest(SyntaxShape::Int, "rest of processes to kill")
|
||||
.switch("force", "forcefully kill the process", Some('f'))
|
||||
.switch("quiet", "won't print anything to the console", Some('q'))
|
||||
.switch("quiet", "won't print anything to the console", Some('q'));
|
||||
|
||||
if cfg!(windows) {
|
||||
return signature;
|
||||
}
|
||||
|
||||
signature.named(
|
||||
"signal",
|
||||
SyntaxShape::Int,
|
||||
"signal decimal number to be sent instead of the default 15 (unsupported on Windows)",
|
||||
Some('s'),
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -53,6 +65,11 @@ impl WholeStreamCommand for Kill {
|
||||
example: "kill --force 12345",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Send INT signal",
|
||||
example: "kill -s 2 12345",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -64,6 +81,7 @@ async fn kill(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
rest,
|
||||
force,
|
||||
quiet,
|
||||
signal,
|
||||
},
|
||||
..,
|
||||
) = args.process().await?;
|
||||
@ -89,7 +107,18 @@ async fn kill(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut cmd = Command::new("kill");
|
||||
|
||||
if *force {
|
||||
if let Some(signal_value) = signal {
|
||||
return Err(ShellError::labeled_error_with_secondary(
|
||||
"mixing force and signal options is not supported",
|
||||
"signal option",
|
||||
signal_value.tag(),
|
||||
"force option",
|
||||
force.tag(),
|
||||
));
|
||||
}
|
||||
cmd.arg("-9");
|
||||
} else if let Some(signal_value) = signal {
|
||||
cmd.arg(format!("-{}", signal_value.item().to_string()));
|
||||
}
|
||||
|
||||
cmd.arg(pid.item().to_string());
|
||||
|
@ -4,21 +4,21 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, UntaggedValue, Value};
|
||||
|
||||
pub struct Count;
|
||||
pub struct Length;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CountArgs {
|
||||
pub struct LengthArgs {
|
||||
column: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Count {
|
||||
impl WholeStreamCommand for Length {
|
||||
fn name(&self) -> &str {
|
||||
"count"
|
||||
"length"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("count").switch(
|
||||
Signature::build("length").switch(
|
||||
"column",
|
||||
"Calculate number of columns in table",
|
||||
Some('c'),
|
||||
@ -31,10 +31,10 @@ impl WholeStreamCommand for Count {
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let (CountArgs { column }, input) = args.process().await?;
|
||||
let (LengthArgs { column }, input) = args.process().await?;
|
||||
let rows: Vec<Value> = input.collect().await;
|
||||
|
||||
let count = if column {
|
||||
let length = if column {
|
||||
if rows.is_empty() {
|
||||
0
|
||||
} else {
|
||||
@ -42,8 +42,8 @@ impl WholeStreamCommand for Count {
|
||||
UntaggedValue::Row(dictionary) => dictionary.length(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Cannot obtain column count",
|
||||
"cannot obtain column count",
|
||||
"Cannot obtain column length",
|
||||
"cannot obtain column length",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
@ -53,19 +53,21 @@ impl WholeStreamCommand for Count {
|
||||
rows.len()
|
||||
};
|
||||
|
||||
Ok(OutputStream::one(UntaggedValue::int(count).into_value(tag)))
|
||||
Ok(OutputStream::one(
|
||||
UntaggedValue::int(length).into_value(tag),
|
||||
))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Count the number of entries in a list",
|
||||
example: "echo [1 2 3 4 5] | count",
|
||||
example: "echo [1 2 3 4 5] | length",
|
||||
result: Some(vec![UntaggedValue::int(5).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Count the number of columns in the calendar table",
|
||||
example: "cal | count -c",
|
||||
example: "cal | length -c",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
@ -74,13 +76,13 @@ impl WholeStreamCommand for Count {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Count;
|
||||
use super::Length;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Count {})
|
||||
test_examples(Length {})
|
||||
}
|
||||
}
|
@ -56,59 +56,70 @@ async fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(args
|
||||
.input
|
||||
.chain(eos)
|
||||
.map(move |item| {
|
||||
.filter_map(move |item| {
|
||||
let leftover_string = leftover_string.clone();
|
||||
async move {
|
||||
match item {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(st)),
|
||||
..
|
||||
} => {
|
||||
let mut leftover_string = leftover_string.lock();
|
||||
|
||||
match item {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(st)),
|
||||
..
|
||||
} => {
|
||||
let mut leftover_string = leftover_string.lock();
|
||||
let mut buffer = leftover_string.clone();
|
||||
buffer.push_str(&st);
|
||||
|
||||
let lo_lines = (&*leftover_string).lines().map(|x| x.to_string());
|
||||
let st_lines = st.lines().map(|x| x.to_string());
|
||||
let mut lines: Vec<String> = lo_lines.chain(st_lines).collect();
|
||||
let mut lines: Vec<String> =
|
||||
buffer.lines().map(|x| x.to_string()).collect();
|
||||
|
||||
leftover_string.clear();
|
||||
leftover_string.clear();
|
||||
|
||||
if !ends_with_line_ending(&st) {
|
||||
if let Some(last) = lines.pop() {
|
||||
leftover_string.push_str(&last);
|
||||
if !ends_with_line_ending(&st) {
|
||||
if let Some(last) = lines.pop() {
|
||||
leftover_string.push_str(&last);
|
||||
}
|
||||
}
|
||||
|
||||
if !lines.is_empty() {
|
||||
let success_lines: Vec<_> = lines
|
||||
.iter()
|
||||
.map(|x| {
|
||||
ReturnSuccess::value(
|
||||
UntaggedValue::string(x).into_untagged_value(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(futures::stream::iter(success_lines))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
let success_lines: Vec<_> = lines
|
||||
.iter()
|
||||
.map(|x| {
|
||||
ReturnSuccess::value(UntaggedValue::string(x).into_untagged_value())
|
||||
})
|
||||
.collect();
|
||||
|
||||
futures::stream::iter(success_lines)
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::EndOfStream),
|
||||
..
|
||||
} => {
|
||||
let st = (&*leftover_string).lock().clone();
|
||||
if !st.is_empty() {
|
||||
futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::string(st).into_untagged_value(),
|
||||
)])
|
||||
} else {
|
||||
futures::stream::iter(vec![])
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::EndOfStream),
|
||||
..
|
||||
} => {
|
||||
let st = (&*leftover_string).lock().clone();
|
||||
if !st.is_empty() {
|
||||
Some(futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::string(st).into_untagged_value(),
|
||||
)]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Value {
|
||||
tag: value_span, ..
|
||||
} => Some(futures::stream::iter(vec![Err(
|
||||
ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
name_span,
|
||||
"value originates from here",
|
||||
value_span,
|
||||
),
|
||||
)])),
|
||||
}
|
||||
Value {
|
||||
tag: value_span, ..
|
||||
} => futures::stream::iter(vec![Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
name_span,
|
||||
"value originates from here",
|
||||
value_span,
|
||||
))]),
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
|
@ -74,6 +74,11 @@ documentation link at https://docs.rs/encoding_rs/0.8.28/encoding_rs/#statics"#
|
||||
example: "open file.csv --encoding iso-8859-1 | from csv",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Lists the contents of a directory (identical to `ls ../projectB`)",
|
||||
example: "open ../projectB",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -99,6 +104,8 @@ async fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let scope = args.scope.clone();
|
||||
let cwd = PathBuf::from(args.shell_manager.path());
|
||||
let shell_manager = args.shell_manager.clone();
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let ctrl_c = args.ctrl_c.clone();
|
||||
|
||||
let (
|
||||
OpenArgs {
|
||||
@ -109,6 +116,17 @@ async fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
_,
|
||||
) = args.process().await?;
|
||||
|
||||
if path.is_dir() {
|
||||
let args = nu_engine::shell::LsArgs {
|
||||
path: Some(path),
|
||||
all: false,
|
||||
long: false,
|
||||
short_names: false,
|
||||
du: false,
|
||||
};
|
||||
return shell_manager.ls(args, name, ctrl_c);
|
||||
}
|
||||
|
||||
// TODO: Remove once Streams are supported everywhere!
|
||||
// As a short term workaround for getting AutoConvert and Bat functionality (Those don't currently support Streams)
|
||||
|
||||
|
@ -143,11 +143,11 @@ async fn maybe_autocd_dir<'a>(
|
||||
// - the command name ends in a path separator, or
|
||||
// - it's not a command on the path and no arguments were given.
|
||||
let name = &cmd.name;
|
||||
let path_name = if name.ends_with(std::path::MAIN_SEPARATOR)
|
||||
let path_name = if name.ends_with(std::path::is_separator)
|
||||
|| (cmd.args.is_empty()
|
||||
&& PathBuf::from(name).is_dir()
|
||||
&& dunce::canonicalize(name).is_ok()
|
||||
&& !crate::commands::classified::external::did_find_command(&name))
|
||||
&& !ctx.host.lock().is_external_cmd(&name))
|
||||
{
|
||||
Some(name)
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_engine::{script, WholeStreamCommand};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::expand_path;
|
||||
@ -50,7 +50,7 @@ pub async fn source(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let contents = std::fs::read_to_string(expand_path(&filename.item).into_owned());
|
||||
match contents {
|
||||
Ok(contents) => {
|
||||
let result = crate::script::run_script_standalone(contents, true, &ctx, false).await;
|
||||
let result = script::run_script_standalone(contents, true, &ctx, false).await;
|
||||
|
||||
if let Err(err) = result {
|
||||
ctx.error(err.into());
|
||||
|
@ -8,14 +8,48 @@ use nu_protocol::{
|
||||
use nu_source::{Tag, Tagged};
|
||||
use nu_value_ext::ValueExt;
|
||||
|
||||
use chrono::{DateTime, FixedOffset, LocalResult, Offset, TimeZone};
|
||||
use chrono::{DateTime, FixedOffset, Local, LocalResult, Offset, TimeZone, Utc};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Arguments {
|
||||
timezone: Option<Tagged<String>>,
|
||||
offset: Option<Tagged<i16>>,
|
||||
format: Option<Tagged<String>>,
|
||||
rest: Vec<ColumnPath>,
|
||||
}
|
||||
|
||||
// In case it may be confused with chrono::TimeZone
|
||||
#[derive(Clone)]
|
||||
enum Zone {
|
||||
Utc,
|
||||
Local,
|
||||
East(u8),
|
||||
West(u8),
|
||||
Error, // we want the nullshell to cast it instead of rust
|
||||
}
|
||||
|
||||
impl Zone {
|
||||
fn new(i: i16) -> Self {
|
||||
if i.abs() <= 12 {
|
||||
// guanranteed here
|
||||
if i >= 0 {
|
||||
Self::East(i as u8) // won't go out of range
|
||||
} else {
|
||||
Self::West(-i as u8) // same here
|
||||
}
|
||||
} else {
|
||||
Self::Error // Out of range
|
||||
}
|
||||
}
|
||||
fn from_string(s: String) -> Self {
|
||||
match s.to_lowercase().as_str() {
|
||||
"utc" | "u" => Self::Utc,
|
||||
"local" | "l" => Self::Local,
|
||||
_ => Self::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[async_trait]
|
||||
@ -26,6 +60,18 @@ impl WholeStreamCommand for SubCommand {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("str to-datetime")
|
||||
.named(
|
||||
"timezone",
|
||||
SyntaxShape::String,
|
||||
"Specify timezone if the input is timestamp, like 'UTC/u' or 'LOCAL/l'",
|
||||
Some('z'),
|
||||
)
|
||||
.named(
|
||||
"offset",
|
||||
SyntaxShape::Int,
|
||||
"Specify timezone by offset if the input is timestamp, like '+8', '-4', prior than timezone",
|
||||
Some('o'),
|
||||
)
|
||||
.named(
|
||||
"format",
|
||||
SyntaxShape::String,
|
||||
@ -63,6 +109,17 @@ impl WholeStreamCommand for SubCommand {
|
||||
example: "echo '20200904_163918+0000' | str to-datetime -f '%Y%m%d_%H%M%S%z'",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Convert to datetime using a specified timezone",
|
||||
example: "echo '1614434140' | str to-datetime -z 'UTC'",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Convert to datetime using a specified timezone offset (between -12 and 12)",
|
||||
example: "echo '1614434140' | str to-datetime -o '+9'",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -71,11 +128,42 @@ impl WholeStreamCommand for SubCommand {
|
||||
struct DatetimeFormat(String);
|
||||
|
||||
async fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let (Arguments { format, rest }, input) = args.process().await?;
|
||||
let (
|
||||
Arguments {
|
||||
timezone,
|
||||
offset,
|
||||
format,
|
||||
rest,
|
||||
},
|
||||
input,
|
||||
) = args.process().await?;
|
||||
|
||||
let column_paths: Vec<_> = rest;
|
||||
|
||||
let options = if let Some(Tagged { item: fmt, .. }) = format {
|
||||
// if zone-offset is specified, then zone will be neglected
|
||||
let zone_options = if let Some(Tagged {
|
||||
item: zone_offset,
|
||||
tag: _tag,
|
||||
}) = offset
|
||||
{
|
||||
Some(Tagged {
|
||||
item: Zone::new(zone_offset),
|
||||
tag: _tag,
|
||||
})
|
||||
} else if let Some(Tagged {
|
||||
item: zone,
|
||||
tag: _tag,
|
||||
}) = timezone
|
||||
{
|
||||
Some(Tagged {
|
||||
item: Zone::from_string(zone),
|
||||
tag: _tag,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let format_options = if let Some(Tagged { item: fmt, .. }) = format {
|
||||
Some(DatetimeFormat(fmt))
|
||||
} else {
|
||||
None
|
||||
@ -84,16 +172,17 @@ async fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(input
|
||||
.map(move |v| {
|
||||
if column_paths.is_empty() {
|
||||
ReturnSuccess::value(action(&v, &options, v.tag())?)
|
||||
ReturnSuccess::value(action(&v, &zone_options, &format_options, v.tag())?)
|
||||
} else {
|
||||
let mut ret = v;
|
||||
|
||||
for path in &column_paths {
|
||||
let options = options.clone();
|
||||
let zone_options = zone_options.clone();
|
||||
let format_options = format_options.clone();
|
||||
|
||||
ret = ret.swap_data_by_column_path(
|
||||
path,
|
||||
Box::new(move |old| action(old, &options, old.tag())),
|
||||
Box::new(move |old| action(old, &zone_options, &format_options, old.tag())),
|
||||
)?;
|
||||
}
|
||||
|
||||
@ -105,12 +194,41 @@ async fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
fn action(
|
||||
input: &Value,
|
||||
options: &Option<DatetimeFormat>,
|
||||
timezone: &Option<Tagged<Zone>>,
|
||||
dateformat: &Option<DatetimeFormat>,
|
||||
tag: impl Into<Tag>,
|
||||
) -> Result<Value, ShellError> {
|
||||
match &input.value {
|
||||
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||
let out = match options {
|
||||
let ts = s.parse::<i64>();
|
||||
// if timezone if specified, first check if the input is a timestamp.
|
||||
if let Some(tz) = timezone {
|
||||
if let Ok(t) = ts {
|
||||
const HOUR: i32 = 3600;
|
||||
let stampout = match tz.item {
|
||||
Zone::Utc => UntaggedValue::date(Utc.timestamp(t, 0)),
|
||||
Zone::Local => UntaggedValue::date(Local.timestamp(t, 0)),
|
||||
Zone::East(i) => {
|
||||
let eastoffset = FixedOffset::east((i as i32) * HOUR);
|
||||
UntaggedValue::date(eastoffset.timestamp(t, 0))
|
||||
}
|
||||
Zone::West(i) => {
|
||||
let westoffset = FixedOffset::west((i as i32) * HOUR);
|
||||
UntaggedValue::date(westoffset.timestamp(t, 0))
|
||||
}
|
||||
Zone::Error => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"could not continue to convert timestamp",
|
||||
"given timezone or offset is invalid",
|
||||
tz.tag().span,
|
||||
));
|
||||
}
|
||||
};
|
||||
return Ok(stampout.into_value(tag));
|
||||
}
|
||||
};
|
||||
// if it's not, continue and negelect the timezone option.
|
||||
let out = match dateformat {
|
||||
Some(dt) => match DateTime::parse_from_str(s, &dt.0) {
|
||||
Ok(d) => UntaggedValue::date(d),
|
||||
Err(reason) => {
|
||||
@ -165,9 +283,9 @@ fn action(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, DatetimeFormat, SubCommand};
|
||||
use super::{action, DatetimeFormat, SubCommand, Zone};
|
||||
use nu_protocol::{Primitive, UntaggedValue};
|
||||
use nu_source::Tag;
|
||||
use nu_source::{Tag, Tagged};
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
@ -183,7 +301,7 @@ mod tests {
|
||||
|
||||
let fmt_options = Some(DatetimeFormat("%d.%m.%Y %H:%M %P %z".to_string()));
|
||||
|
||||
let actual = action(&date_str, &fmt_options, Tag::unknown()).unwrap();
|
||||
let actual = action(&date_str, &None, &fmt_options, Tag::unknown()).unwrap();
|
||||
|
||||
match actual.value {
|
||||
UntaggedValue::Primitive(Primitive::Date(_)) => {}
|
||||
@ -194,7 +312,35 @@ mod tests {
|
||||
#[test]
|
||||
fn takes_iso8601_date_format() {
|
||||
let date_str = string("2020-08-04T16:39:18+00:00");
|
||||
let actual = action(&date_str, &None, Tag::unknown()).unwrap();
|
||||
let actual = action(&date_str, &None, &None, Tag::unknown()).unwrap();
|
||||
match actual.value {
|
||||
UntaggedValue::Primitive(Primitive::Date(_)) => {}
|
||||
_ => panic!("Didn't convert to date"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn takes_timestamp_offset() {
|
||||
let date_str = string("1614434140");
|
||||
let timezone_option = Some(Tagged {
|
||||
item: Zone::East(8),
|
||||
tag: Tag::unknown(),
|
||||
});
|
||||
let actual = action(&date_str, &timezone_option, &None, Tag::unknown()).unwrap();
|
||||
match actual.value {
|
||||
UntaggedValue::Primitive(Primitive::Date(_)) => {}
|
||||
_ => panic!("Didn't convert to date"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn takes_timestamp() {
|
||||
let date_str = string("1614434140");
|
||||
let timezone_option = Some(Tagged {
|
||||
item: Zone::Local,
|
||||
tag: Tag::unknown(),
|
||||
});
|
||||
let actual = action(&date_str, &timezone_option, &None, Tag::unknown()).unwrap();
|
||||
match actual.value {
|
||||
UntaggedValue::Primitive(Primitive::Date(_)) => {}
|
||||
_ => panic!("Didn't convert to date"),
|
||||
@ -207,7 +353,7 @@ mod tests {
|
||||
|
||||
let fmt_options = Some(DatetimeFormat("%d.%m.%Y %H:%M %P %z".to_string()));
|
||||
|
||||
let actual = action(&date_str, &fmt_options, Tag::unknown());
|
||||
let actual = action(&date_str, &None, &fmt_options, Tag::unknown());
|
||||
|
||||
assert!(actual.is_err());
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_table::{draw_table, Alignment, StyledString, TextStyle};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::time::Instant;
|
||||
|
||||
#[cfg(feature = "table-pager")]
|
||||
use {
|
||||
futures::future::join,
|
||||
|
@ -4,16 +4,16 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct ToCSV;
|
||||
pub struct ToCsv;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ToCSVArgs {
|
||||
pub struct ToCsvArgs {
|
||||
noheaders: bool,
|
||||
separator: Option<Value>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToCSV {
|
||||
impl WholeStreamCommand for ToCsv {
|
||||
fn name(&self) -> &str {
|
||||
"to csv"
|
||||
}
|
||||
@ -45,7 +45,7 @@ impl WholeStreamCommand for ToCSV {
|
||||
async fn to_csv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let (
|
||||
ToCSVArgs {
|
||||
ToCsvArgs {
|
||||
separator,
|
||||
noheaders,
|
||||
},
|
||||
@ -80,12 +80,12 @@ async fn to_csv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::ToCSV;
|
||||
use super::ToCsv;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToCSV {})
|
||||
test_examples(ToCsv {})
|
||||
}
|
||||
}
|
||||
|
@ -79,10 +79,10 @@ impl Default for HtmlTheme {
|
||||
#[folder = "assets/"]
|
||||
struct Assets;
|
||||
|
||||
pub struct ToHTML;
|
||||
pub struct ToHtml;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ToHTMLArgs {
|
||||
pub struct ToHtmlArgs {
|
||||
html_color: bool,
|
||||
no_color: bool,
|
||||
dark: bool,
|
||||
@ -92,7 +92,7 @@ pub struct ToHTMLArgs {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToHTML {
|
||||
impl WholeStreamCommand for ToHtml {
|
||||
fn name(&self) -> &str {
|
||||
"to html"
|
||||
}
|
||||
@ -271,7 +271,7 @@ fn get_list_of_theme_names() -> Vec<String> {
|
||||
async fn to_html(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
let (
|
||||
ToHTMLArgs {
|
||||
ToHtmlArgs {
|
||||
html_color,
|
||||
no_color,
|
||||
dark,
|
||||
@ -758,6 +758,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToHTML {})
|
||||
test_examples(ToHtml {})
|
||||
}
|
||||
}
|
||||
|
@ -7,15 +7,15 @@ use nu_protocol::{
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
|
||||
pub struct ToJSON;
|
||||
pub struct ToJson;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ToJSONArgs {
|
||||
pub struct ToJsonArgs {
|
||||
pretty: Option<Value>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToJSON {
|
||||
impl WholeStreamCommand for ToJson {
|
||||
fn name(&self) -> &str {
|
||||
"to json"
|
||||
}
|
||||
@ -160,7 +160,7 @@ fn json_list(input: &[Value]) -> Result<Vec<serde_json::Value>, ShellError> {
|
||||
|
||||
async fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
let (ToJSONArgs { pretty }, input) = args.process().await?;
|
||||
let (ToJsonArgs { pretty }, input) = args.process().await?;
|
||||
let name_span = name_tag.span;
|
||||
let input: Vec<Value> = input.collect().await;
|
||||
|
||||
@ -256,12 +256,12 @@ async fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::ToJSON;
|
||||
use super::ToJson;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToJSON {})
|
||||
test_examples(ToJson {})
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::{CoerceInto, ShellError};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UnspannedPathMember, UntaggedValue, Value};
|
||||
|
||||
pub struct ToTOML;
|
||||
pub struct ToToml;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToTOML {
|
||||
impl WholeStreamCommand for ToToml {
|
||||
fn name(&self) -> &str {
|
||||
"to toml"
|
||||
}
|
||||
@ -195,7 +195,7 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToTOML {})
|
||||
test_examples(ToToml {})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -4,15 +4,15 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::Signature;
|
||||
|
||||
pub struct ToTSV;
|
||||
pub struct ToTsv;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ToTSVArgs {
|
||||
pub struct ToTsvArgs {
|
||||
noheaders: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToTSV {
|
||||
impl WholeStreamCommand for ToTsv {
|
||||
fn name(&self) -> &str {
|
||||
"to tsv"
|
||||
}
|
||||
@ -36,7 +36,7 @@ impl WholeStreamCommand for ToTSV {
|
||||
|
||||
async fn to_tsv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let (ToTSVArgs { noheaders }, input) = args.process().await?;
|
||||
let (ToTsvArgs { noheaders }, input) = args.process().await?;
|
||||
|
||||
to_delimited_data(noheaders, '\t', "TSV", input, name).await
|
||||
}
|
||||
@ -44,12 +44,12 @@ async fn to_tsv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::ToTSV;
|
||||
use super::ToTsv;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToTSV {})
|
||||
test_examples(ToTsv {})
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
|
||||
pub struct ToURL;
|
||||
pub struct ToUrl;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToURL {
|
||||
impl WholeStreamCommand for ToUrl {
|
||||
fn name(&self) -> &str {
|
||||
"to url"
|
||||
}
|
||||
@ -76,12 +76,12 @@ async fn to_url(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::ToURL;
|
||||
use super::ToUrl;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToURL {})
|
||||
test_examples(ToUrl {})
|
||||
}
|
||||
}
|
||||
|
@ -8,15 +8,15 @@ use std::collections::HashSet;
|
||||
use std::io::Cursor;
|
||||
use std::io::Write;
|
||||
|
||||
pub struct ToXML;
|
||||
pub struct ToXml;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ToXMLArgs {
|
||||
pub struct ToXmlArgs {
|
||||
pretty: Option<Value>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToXML {
|
||||
impl WholeStreamCommand for ToXml {
|
||||
fn name(&self) -> &str {
|
||||
"to xml"
|
||||
}
|
||||
@ -135,7 +135,7 @@ pub fn write_xml_events<W: Write>(
|
||||
async fn to_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
let name_span = name_tag.span;
|
||||
let (ToXMLArgs { pretty }, input) = args.process().await?;
|
||||
let (ToXmlArgs { pretty }, input) = args.process().await?;
|
||||
let input: Vec<Value> = input.collect().await;
|
||||
|
||||
let to_process_input = match input.len() {
|
||||
@ -189,12 +189,12 @@ async fn to_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::ToXML;
|
||||
use super::ToXml;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToXML {})
|
||||
test_examples(ToXml {})
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::{CoerceInto, ShellError};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UnspannedPathMember, UntaggedValue, Value};
|
||||
|
||||
pub struct ToYAML;
|
||||
pub struct ToYaml;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToYAML {
|
||||
impl WholeStreamCommand for ToYaml {
|
||||
fn name(&self) -> &str {
|
||||
"to yaml"
|
||||
}
|
||||
@ -164,12 +164,12 @@ async fn to_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::ToYAML;
|
||||
use super::ToYaml;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToYAML {})
|
||||
test_examples(ToYaml {})
|
||||
}
|
||||
}
|
||||
|
@ -6,14 +6,12 @@ mod stub_generate;
|
||||
|
||||
use double_echo::Command as DoubleEcho;
|
||||
use double_ls::Command as DoubleLs;
|
||||
use stub_generate::{mock_path, Command as StubOpen};
|
||||
|
||||
use nu_engine::basic_evaluation_context;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ParserScope;
|
||||
use nu_protocol::hir::ClassifiedBlock;
|
||||
use nu_protocol::{ShellTypeName, Value};
|
||||
use nu_source::AnchorLocation;
|
||||
use stub_generate::{mock_path, Command as StubOpen};
|
||||
|
||||
use crate::commands::{
|
||||
Append, BuildString, Each, Echo, First, Get, Keep, Last, Let, Nth, Select, StrCollect, Wrap,
|
||||
@ -26,7 +24,7 @@ use futures::executor::block_on;
|
||||
pub fn test_examples(cmd: Command) -> Result<(), ShellError> {
|
||||
let examples = cmd.examples();
|
||||
|
||||
let base_context = basic_evaluation_context()?;
|
||||
let base_context = EvaluationContext::basic()?;
|
||||
|
||||
base_context.add_commands(vec![
|
||||
// Command Doubles
|
||||
@ -92,7 +90,7 @@ pub fn test_examples(cmd: Command) -> Result<(), ShellError> {
|
||||
pub fn test(cmd: impl WholeStreamCommand + 'static) -> Result<(), ShellError> {
|
||||
let examples = cmd.examples();
|
||||
|
||||
let base_context = basic_evaluation_context()?;
|
||||
let base_context = EvaluationContext::basic()?;
|
||||
|
||||
base_context.add_commands(vec![
|
||||
whole_stream_command(Echo {}),
|
||||
@ -149,7 +147,7 @@ pub fn test(cmd: impl WholeStreamCommand + 'static) -> Result<(), ShellError> {
|
||||
pub fn test_anchors(cmd: Command) -> Result<(), ShellError> {
|
||||
let examples = cmd.examples();
|
||||
|
||||
let base_context = basic_evaluation_context()?;
|
||||
let base_context = EvaluationContext::basic()?;
|
||||
|
||||
base_context.add_commands(vec![
|
||||
// Minimal restricted commands to aid in testing
|
||||
|
@ -8,15 +8,11 @@ extern crate indexmap;
|
||||
mod prelude;
|
||||
pub mod commands;
|
||||
mod futures;
|
||||
pub mod maybe_print_errors;
|
||||
pub mod script;
|
||||
pub mod utils;
|
||||
|
||||
#[cfg(test)]
|
||||
mod examples;
|
||||
|
||||
pub use crate::maybe_print_errors::maybe_print_errors;
|
||||
|
||||
pub use nu_data::config;
|
||||
pub use nu_data::dict::TaggedListBuilder;
|
||||
pub use nu_data::primitive;
|
||||
|
@ -1,17 +0,0 @@
|
||||
use nu_engine::EvaluationContext;
|
||||
use nu_source::Text;
|
||||
|
||||
pub fn maybe_print_errors(context: &EvaluationContext, source: Text) -> bool {
|
||||
let errors = context.current_errors.clone();
|
||||
let mut errors = errors.lock();
|
||||
|
||||
if errors.len() > 0 {
|
||||
let error = errors[0].clone();
|
||||
*errors = vec![];
|
||||
|
||||
crate::script::print_err(error, &source, context);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
@ -46,7 +46,6 @@ macro_rules! trace_out_stream {
|
||||
}};
|
||||
}
|
||||
|
||||
pub(crate) use crate::commands::command::RunnableContext;
|
||||
pub(crate) use async_trait::async_trait;
|
||||
pub(crate) use bigdecimal::BigDecimal;
|
||||
pub(crate) use futures::{Stream, StreamExt};
|
||||
@ -58,11 +57,12 @@ pub(crate) use nu_engine::EvaluationContext;
|
||||
pub(crate) use nu_engine::Example;
|
||||
pub(crate) use nu_engine::Host;
|
||||
pub(crate) use nu_engine::RawCommandArgs;
|
||||
pub(crate) use nu_engine::RunnableContext;
|
||||
pub(crate) use nu_engine::ShellManager;
|
||||
pub(crate) use nu_engine::{get_full_help, CommandArgs, Scope, WholeStreamCommand};
|
||||
pub(crate) use nu_parser::ParserScope;
|
||||
pub(crate) use nu_protocol::{out, row};
|
||||
pub(crate) use nu_source::{AnchorLocation, PrettyDebug, Span, SpannedItem, Tag, TaggedItem, Text};
|
||||
pub(crate) use nu_source::{AnchorLocation, PrettyDebug, Span, SpannedItem, Tag, TaggedItem};
|
||||
pub(crate) use nu_stream::ToInputStream;
|
||||
pub(crate) use nu_stream::{InputStream, Interruptible, OutputStream};
|
||||
pub(crate) use nu_value_ext::ValueExt;
|
||||
@ -71,7 +71,7 @@ pub(crate) use num_traits::cast::ToPrimitive;
|
||||
pub(crate) use serde::Deserialize;
|
||||
pub(crate) use std::collections::VecDeque;
|
||||
pub(crate) use std::future::Future;
|
||||
pub(crate) use std::sync::atomic::{AtomicBool, Ordering};
|
||||
pub(crate) use std::sync::atomic::AtomicBool;
|
||||
pub(crate) use std::sync::Arc;
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
|
@ -17,6 +17,21 @@ pub fn nonu() {
|
||||
args().iter().skip(1).for_each(|arg| print!("{}", arg));
|
||||
}
|
||||
|
||||
pub fn repeater() {
|
||||
let mut stdout = io::stdout();
|
||||
let args = args();
|
||||
let mut args = args.iter().skip(1);
|
||||
let letter = args.next().expect("needs a character to iterate");
|
||||
let count = args.next().expect("need the number of times to iterate");
|
||||
|
||||
let count: u64 = count.parse().expect("can't convert count to number");
|
||||
|
||||
for _ in 0..count {
|
||||
let _ = write!(stdout, "{}", letter);
|
||||
}
|
||||
let _ = stdout.flush();
|
||||
}
|
||||
|
||||
pub fn iecho() {
|
||||
// println! panics if stdout gets closed, whereas writeln gives us an error
|
||||
let mut stdout = io::stdout();
|
||||
|
@ -1,29 +1,21 @@
|
||||
use nu_test_support::fs::Stub::FileWithContentToBeTrimmed;
|
||||
use nu_test_support::playground::Playground;
|
||||
use nu_test_support::{nu, pipeline};
|
||||
use nu_test_support::pipeline as input;
|
||||
use nu_test_support::playground::{says, Playground};
|
||||
|
||||
use hamcrest2::assert_that;
|
||||
use hamcrest2::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn adds_a_row_to_the_end() {
|
||||
Playground::setup("append_test_1", |dirs, sandbox| {
|
||||
sandbox.with_files(vec![FileWithContentToBeTrimmed(
|
||||
"los_tres_caballeros.txt",
|
||||
r#"
|
||||
Andrés N. Robalino
|
||||
Jonathan Turner
|
||||
Yehuda Katz
|
||||
"#,
|
||||
)]);
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
open los_tres_caballeros.txt
|
||||
| lines
|
||||
Playground::setup("append_test_1", |_, nu| {
|
||||
assert_that!(
|
||||
nu.pipeline(&input(
|
||||
r#"
|
||||
echo [ "Andrés N. Robalino", "Jonathan Turner", "Yehuda Katz" ]
|
||||
| append "pollo loco"
|
||||
| nth 3
|
||||
"#
|
||||
));
|
||||
|
||||
assert_eq!(actual.out, "pollo loco");
|
||||
"#
|
||||
)),
|
||||
says().to_stdout("pollo loco")
|
||||
);
|
||||
})
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -33,7 +33,7 @@ fn cal_friday_the_thirteenths_in_2015() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
cal --full-year 2015 | default friday 0 | where friday == 13 | count
|
||||
cal --full-year 2015 | default friday 0 | where friday == 13 | length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -45,7 +45,7 @@ fn cal_rows_in_2020() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
cal --full-year 2020 | count
|
||||
cal --full-year 2020 | length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -25,7 +25,7 @@ fn discards_rows_where_given_column_is_empty() {
|
||||
open los_tres_amigos.json
|
||||
| get amigos
|
||||
| compact rusty_luck
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -41,7 +41,7 @@ fn discards_empty_rows_by_default() {
|
||||
echo "[1,2,3,14,null]"
|
||||
| from json
|
||||
| compact
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -26,7 +26,7 @@ fn adds_row_data_if_column_missing() {
|
||||
| get amigos
|
||||
| default rusty_luck 1
|
||||
| where rusty_luck == 1
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -13,7 +13,7 @@ fn columns() {
|
||||
]
|
||||
| drop column
|
||||
| get
|
||||
| count
|
||||
| length
|
||||
"#)
|
||||
);
|
||||
|
||||
@ -62,7 +62,7 @@ fn rows() {
|
||||
|
||||
#[test]
|
||||
fn more_rows_than_table_has() {
|
||||
let actual = nu!(cwd: ".", "date | drop 50 | count");
|
||||
let actual = nu!(cwd: ".", "date | drop 50 | length");
|
||||
|
||||
assert_eq!(actual.out, "0");
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ fn reports_emptiness() {
|
||||
| get are_empty
|
||||
| empty? check
|
||||
| where check
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -17,7 +17,7 @@ fn gets_first_rows_by_amount() {
|
||||
r#"
|
||||
ls
|
||||
| first 3
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -40,7 +40,7 @@ fn gets_all_rows_if_amount_higher_than_all_rows() {
|
||||
r#"
|
||||
ls
|
||||
| first 99
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -58,7 +58,7 @@ fn gets_first_row_when_no_amount_given() {
|
||||
r#"
|
||||
ls
|
||||
| first
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -71,7 +71,7 @@ fn flatten_row_column_explicitly() {
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
"open katz.json | flatten people | where name == Andres | count"
|
||||
"open katz.json | flatten people | where name == Andres | length"
|
||||
);
|
||||
|
||||
assert_eq!(actual.out, "1");
|
||||
@ -105,7 +105,7 @@ fn flatten_row_columns_having_same_column_names_flats_separately() {
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
"open katz.json | flatten | flatten people city | get city_name | count"
|
||||
"open katz.json | flatten | flatten people city | get city_name | length"
|
||||
);
|
||||
|
||||
assert_eq!(actual.out, "4");
|
||||
@ -139,7 +139,7 @@ fn flatten_table_columns_explicitly() {
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
"open katz.json | flatten city | where people.name == Katz | count"
|
||||
"open katz.json | flatten city | where people.name == Katz | length"
|
||||
);
|
||||
|
||||
assert_eq!(actual.out, "2");
|
||||
|
@ -89,7 +89,7 @@ fn column_paths_are_either_double_quoted_or_regular_unquoted_words_separated_by_
|
||||
r#"
|
||||
open sample.toml
|
||||
| get package."9999"
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -151,24 +151,12 @@ fn errors_fetching_by_column_not_present() {
|
||||
"#
|
||||
));
|
||||
|
||||
assert!(
|
||||
actual.err.contains("Unknown column"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(
|
||||
actual.err.contains("There isn't a column named 'taco'"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(
|
||||
actual.err.contains("Perhaps you meant 'taconushell'?"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(
|
||||
actual
|
||||
.err
|
||||
.contains("Columns available: pizzanushell, taconushell"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(actual.err.contains("Unknown column"),);
|
||||
assert!(actual.err.contains("There isn't a column named 'taco'"),);
|
||||
assert!(actual.err.contains("Perhaps you meant 'taconushell'?"),);
|
||||
assert!(actual
|
||||
.err
|
||||
.contains("Columns available: pizzanushell, taconushell"),);
|
||||
})
|
||||
}
|
||||
|
||||
@ -191,20 +179,11 @@ fn errors_fetching_by_column_using_a_number() {
|
||||
"#
|
||||
));
|
||||
|
||||
assert!(
|
||||
actual.err.contains("No rows available"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(
|
||||
actual.err.contains("A row at '0' can't be indexed."),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(
|
||||
actual
|
||||
.err
|
||||
.contains("Appears to contain columns. Columns available: 0"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
)
|
||||
assert!(actual.err.contains("No rows available"),);
|
||||
assert!(actual.err.contains("A row at '0' can't be indexed."),);
|
||||
assert!(actual
|
||||
.err
|
||||
.contains("Appears to contain columns. Columns available: 0"),)
|
||||
})
|
||||
}
|
||||
#[test]
|
||||
@ -226,18 +205,9 @@ fn errors_fetching_by_index_out_of_bounds() {
|
||||
"#
|
||||
));
|
||||
|
||||
assert!(
|
||||
actual.err.contains("Row not found"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(
|
||||
actual.err.contains("There isn't a row indexed at 3"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(
|
||||
actual.err.contains("The table only has 3 rows (0 to 2)"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
)
|
||||
assert!(actual.err.contains("Row not found"),);
|
||||
assert!(actual.err.contains("There isn't a row indexed at 3"),);
|
||||
assert!(actual.err.contains("The table only has 3 rows (0 to 2)"),)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ fn groups() {
|
||||
open los_tres_caballeros.csv
|
||||
| group-by rusty_at
|
||||
| get "10/11/2013"
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -83,3 +83,16 @@ fn error_use_both_flags() {
|
||||
.err
|
||||
.contains("only one of --decode and --encode flags can be used"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn md5_works_with_file() {
|
||||
let actual = nu!(
|
||||
cwd: "tests/fixtures/formats", pipeline(
|
||||
r#"
|
||||
open sample.db | hash md5
|
||||
"#
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(actual.out, "4de97601d232c427977ef11db396c951");
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
use nu_test_support::{nu, pipeline};
|
||||
|
||||
#[test]
|
||||
fn help_commands_count() {
|
||||
fn help_commands_length() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
help commands | count
|
||||
help commands | length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -16,11 +16,11 @@ fn help_commands_count() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn help_generate_docs_count() {
|
||||
fn help_generate_docs_length() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
help generate_docs | flatten | count
|
||||
help generate_docs | flatten | length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -27,7 +27,7 @@ fn gets_last_rows_by_amount() {
|
||||
r#"
|
||||
ls
|
||||
| last 3
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -45,7 +45,7 @@ fn gets_last_row_when_no_amount_given() {
|
||||
r#"
|
||||
ls
|
||||
| last
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -58,7 +58,7 @@ fn requests_more_rows_than_table_has() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
date | last 50 | count
|
||||
date | last 50 | length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
use nu_test_support::{nu, pipeline};
|
||||
|
||||
#[test]
|
||||
fn count_columns_in_cal_table() {
|
||||
fn length_columns_in_cal_table() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
cal | count -c
|
||||
cal | length -c
|
||||
"#
|
||||
));
|
||||
|
||||
@ -13,11 +13,11 @@ fn count_columns_in_cal_table() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn count_columns_no_rows() {
|
||||
fn length_columns_no_rows() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
echo [] | count -c
|
||||
echo [] | length -c
|
||||
"#
|
||||
));
|
||||
|
@ -42,9 +42,9 @@ fn lines_multi_value_split() {
|
||||
open sample-simple.json
|
||||
| get first second
|
||||
| lines
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
assert_eq!(actual.out, "6");
|
||||
assert_eq!(actual.out, "5");
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use nu_test_support::fs::Stub::EmptyFile;
|
||||
use nu_test_support::playground::{Dirs, Playground};
|
||||
use nu_test_support::playground::Playground;
|
||||
use nu_test_support::{nu, pipeline};
|
||||
|
||||
#[test]
|
||||
@ -15,7 +15,7 @@ fn lists_regular_files() {
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -37,7 +37,7 @@ fn lists_regular_files_using_asterisk_wildcard() {
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls *.txt
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -59,7 +59,7 @@ fn lists_regular_files_using_question_mark_wildcard() {
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls *.??.txt
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -88,7 +88,7 @@ fn lists_all_files_in_directories_from_stream() {
|
||||
r#"
|
||||
echo dir_a dir_b
|
||||
| each { ls $it }
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -105,7 +105,7 @@ fn does_not_fail_if_glob_matches_empty_directory() {
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls dir_a
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -142,7 +142,7 @@ fn list_files_from_two_parents_up_using_multiple_dots() {
|
||||
let actual = nu!(
|
||||
cwd: dirs.test().join("foo/bar"),
|
||||
r#"
|
||||
ls ... | count
|
||||
ls ... | length
|
||||
"#
|
||||
);
|
||||
|
||||
@ -165,7 +165,7 @@ fn lists_hidden_file_when_explicitly_specified() {
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls .testdotfile
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -199,7 +199,7 @@ fn lists_all_hidden_files_when_glob_contains_dot() {
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls **/.*
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -236,7 +236,7 @@ fn lists_all_hidden_files_when_glob_does_not_contain_dot() {
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls **/*
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -259,7 +259,7 @@ fn lists_files_including_starting_with_dot() {
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls -a
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -269,61 +269,57 @@ fn lists_files_including_starting_with_dot() {
|
||||
|
||||
#[test]
|
||||
fn list_all_columns() {
|
||||
Playground::setup(
|
||||
"ls_test_all_columns",
|
||||
|dirs: Dirs, sandbox: &mut Playground| {
|
||||
sandbox.with_files(vec![
|
||||
EmptyFile("Leonardo.yaml"),
|
||||
EmptyFile("Raphael.json"),
|
||||
EmptyFile("Donatello.xml"),
|
||||
EmptyFile("Michelangelo.txt"),
|
||||
]);
|
||||
// Normal Operation
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
"ls | get | to md"
|
||||
);
|
||||
let expected = ["name", "type", "size", "modified"].join("");
|
||||
assert_eq!(actual.out, expected, "column names are incorrect for ls");
|
||||
// Long
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
"ls -l | get | to md"
|
||||
);
|
||||
let expected = {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
[
|
||||
"name",
|
||||
"type",
|
||||
"target",
|
||||
"num_links",
|
||||
"inode",
|
||||
"readonly",
|
||||
"mode",
|
||||
"uid",
|
||||
"group",
|
||||
"size",
|
||||
"created",
|
||||
"accessed",
|
||||
"modified",
|
||||
]
|
||||
.join("")
|
||||
}
|
||||
Playground::setup("ls_test_all_columns", |dirs, sandbox| {
|
||||
sandbox.with_files(vec![
|
||||
EmptyFile("Leonardo.yaml"),
|
||||
EmptyFile("Raphael.json"),
|
||||
EmptyFile("Donatello.xml"),
|
||||
EmptyFile("Michelangelo.txt"),
|
||||
]);
|
||||
// Normal Operation
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
"ls | get | to md"
|
||||
);
|
||||
let expected = ["name", "type", "size", "modified"].join("");
|
||||
assert_eq!(actual.out, expected, "column names are incorrect for ls");
|
||||
// Long
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
"ls -l | get | to md"
|
||||
);
|
||||
let expected = {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
[
|
||||
"name",
|
||||
"type",
|
||||
"target",
|
||||
"num_links",
|
||||
"inode",
|
||||
"readonly",
|
||||
"mode",
|
||||
"uid",
|
||||
"group",
|
||||
"size",
|
||||
"created",
|
||||
"accessed",
|
||||
"modified",
|
||||
]
|
||||
.join("")
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
[
|
||||
"name", "type", "target", "readonly", "size", "created", "accessed",
|
||||
"modified",
|
||||
]
|
||||
.join("")
|
||||
}
|
||||
};
|
||||
assert_eq!(
|
||||
actual.out, expected,
|
||||
"column names are incorrect for ls long"
|
||||
);
|
||||
},
|
||||
);
|
||||
#[cfg(windows)]
|
||||
{
|
||||
[
|
||||
"name", "type", "target", "readonly", "size", "created", "accessed", "modified",
|
||||
]
|
||||
.join("")
|
||||
}
|
||||
};
|
||||
assert_eq!(
|
||||
actual.out, expected,
|
||||
"column names are incorrect for ls long"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ fn show_created_paths() {
|
||||
pipeline(
|
||||
r#"
|
||||
mkdir -s dir_1 dir_2 dir_3
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -1,11 +1,7 @@
|
||||
mod append;
|
||||
mod autoenv;
|
||||
mod autoenv_trust;
|
||||
mod autoenv_untrust;
|
||||
mod cal;
|
||||
mod cd;
|
||||
mod compact;
|
||||
mod count;
|
||||
mod cp;
|
||||
mod def;
|
||||
mod default;
|
||||
@ -28,6 +24,7 @@ mod insert;
|
||||
mod into_int;
|
||||
mod keep;
|
||||
mod last;
|
||||
mod length;
|
||||
mod lines;
|
||||
mod ls;
|
||||
mod math;
|
||||
|
@ -28,7 +28,7 @@ fn selects_many_rows() {
|
||||
ls
|
||||
| get name
|
||||
| nth 1 0
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use nu_test_support::fs::Stub::EmptyFile;
|
||||
use nu_test_support::fs::Stub::FileWithContentToBeTrimmed;
|
||||
use nu_test_support::playground::Playground;
|
||||
use nu_test_support::{nu, pipeline};
|
||||
@ -230,3 +231,24 @@ fn errors_if_file_not_found() {
|
||||
expected
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_dir_is_ls() {
|
||||
Playground::setup("open_dir", |dirs, sandbox| {
|
||||
sandbox.with_files(vec![
|
||||
EmptyFile("yehuda.txt"),
|
||||
EmptyFile("jonathan.txt"),
|
||||
EmptyFile("andres.txt"),
|
||||
]);
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
open .
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
assert_eq!(actual.out, "3");
|
||||
})
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ fn rolls_4_roll() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
random dice -d 4 -s 10 | count
|
||||
random dice -d 4 -s 10 | length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -36,7 +36,7 @@ fn selects_some_rows() {
|
||||
ls
|
||||
| get name
|
||||
| range 1..2
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -23,7 +23,7 @@ fn changes_the_column_name() {
|
||||
| wrap name
|
||||
| rename mosqueteros
|
||||
| get mosqueteros
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -53,7 +53,7 @@ fn keeps_remaining_original_names_given_less_new_names_than_total_original_names
|
||||
| default hit "arepa!"
|
||||
| rename mosqueteros
|
||||
| get hit
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
@ -83,13 +83,7 @@ fn errors_if_no_columns_present() {
|
||||
"#
|
||||
));
|
||||
|
||||
assert!(
|
||||
actual.err.contains("no column names available"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(
|
||||
actual.err.contains("can't rename"),
|
||||
format!("actual: {:?}", actual.err)
|
||||
);
|
||||
assert!(actual.err.contains("no column names available"));
|
||||
assert!(actual.err.contains("can't rename"));
|
||||
})
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ fn allows_if_given_unknown_column_name_is_missing() {
|
||||
[Yehuda Katz 10/11/2013 A]
|
||||
]
|
||||
| select rrusty_at first_name
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -22,7 +22,7 @@ fn splits() {
|
||||
| group-by rusty_at
|
||||
| split-by type
|
||||
| get A."10/11/2013"
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -19,7 +19,7 @@ fn to_row() {
|
||||
| lines
|
||||
| str trim
|
||||
| split row ","
|
||||
| count
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
|
@ -22,7 +22,7 @@ fn removes_duplicate_rows() {
|
||||
r#"
|
||||
open los_tres_caballeros.csv
|
||||
| uniq
|
||||
| count
|
||||
| length
|
||||
|
||||
"#
|
||||
));
|
||||
@ -52,7 +52,7 @@ fn uniq_values() {
|
||||
open los_tres_caballeros.csv
|
||||
| select type
|
||||
| uniq
|
||||
| count
|
||||
| length
|
||||
|
||||
"#
|
||||
));
|
||||
@ -117,7 +117,7 @@ fn nested_json_structures() {
|
||||
r#"
|
||||
open nested_json_structures.json
|
||||
| uniq
|
||||
| count
|
||||
| length
|
||||
|
||||
"#
|
||||
));
|
||||
@ -133,7 +133,7 @@ fn uniq_when_keys_out_of_order() {
|
||||
echo '[{"a": "a", "b": [1,2,3]},{"b": [1,2,3], "a": "a"}]'
|
||||
| from json
|
||||
| uniq
|
||||
| count
|
||||
| length
|
||||
|
||||
"#
|
||||
));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user