From e626522b3aee762fac4eed652d44a2d2d71f4962 Mon Sep 17 00:00:00 2001 From: Luccas Mateus Date: Fri, 16 Oct 2020 14:15:40 -0300 Subject: [PATCH] LS support for other number formatting (#2650) * make sort-by fail gracefully if mismatched types are compared * Added a test to check if sorted-by with invalid types exists gracefully * Linter changes * removed redundant pattern matching * Changed the error message * Added a comma after every argument * Changed the test to accomodate the new err messages * Err message for sort-by invalid types now shows the mismatched types * Lints problems * Changed unwrap to expect * Added the -f flag to rm command Now when you a use rm -f there will be no error message, even if the file doesnt actually exist * Lint problems * Fixed the wrong line * Removed println * Spelling mistake * Fix problems when you mv a file into itself * Lint mistakes * Remove unecessary filtering in most cases * Allow the removal of sockets * Conditional compilations to systems without socket * Add a size-format option to ls command * Added kib and mib formating * Make patterns lowercase * New subcommand to format, filesize * Forgot the linter once more * Remove the ls changes since its no longer needed * CI mistakes * Lint stuff * Fix lint * Added formatting for bytes * fix lint * Changed the usage comment --- crates/nu-cli/src/cli.rs | 1 + crates/nu-cli/src/commands.rs | 2 +- .../commands/{format.rs => format/command.rs} | 0 .../src/commands/format/format_filesize.rs | 194 ++++++++++++++++++ crates/nu-cli/src/commands/format/mod.rs | 5 + crates/nu-cli/tests/commands/format.rs | 25 +++ 6 files changed, 226 insertions(+), 1 deletion(-) rename crates/nu-cli/src/commands/{format.rs => format/command.rs} (100%) create mode 100644 crates/nu-cli/src/commands/format/format_filesize.rs create mode 100644 crates/nu-cli/src/commands/format/mod.rs diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index f18c2caefa..e3c5d2d478 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -180,6 +180,7 @@ pub fn create_default_context(interactive: bool) -> Result, +} + +#[async_trait] +impl WholeStreamCommand for FileSize { + fn name(&self) -> &str { + "format filesize" + } + + fn signature(&self) -> Signature { + Signature::build("format filesize") + .required( + "field", + SyntaxShape::ColumnPath, + "the name of the column to update", + ) + .required( + "format value", + SyntaxShape::String, + "the format into which convert the filesizes", + ) + } + + fn usage(&self) -> &str { + "Converts a column of filesizes to some specified format" + } + + async fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + filesize(args, registry).await + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Convert the size row to KB", + example: "ls | format filesize size KB", + result: None, + }, + Example { + description: "Convert the apparent row to B", + example: "du | format filesize apparent B", + result: None, + }, + ] + } +} + +async fn process_row( + input: Value, + format: Tagged, + field: Arc, +) -> Result { + Ok({ + let replace_for = get_data_by_column_path(&input, &field, move |_, _, error| error); + match replace_for { + Ok(s) => match convert_bytes_to_string_using_format(s, format) { + Ok(b) => OutputStream::one(ReturnSuccess::value( + input.replace_data_at_column_path(&field, b).expect("Given that the existance check was already done, this souldn't trigger never"), + )), + Err(e) => OutputStream::one(Err(e)), + }, + Err(e) => OutputStream::one(Err(e)), + } + }) +} + +async fn filesize( + raw_args: CommandArgs, + registry: &CommandRegistry, +) -> Result { + let registry = registry.clone(); + let (Arguments { field, format }, input) = raw_args.process(®istry).await?; + let field = Arc::new(field); + + Ok(input + .then(move |input| { + let format = format.clone(); + let field = field.clone(); + + async { + match process_row(input, format, field).await { + Ok(s) => s, + Err(e) => OutputStream::one(Err(e)), + } + } + }) + .flatten() + .to_output_stream()) +} + +fn convert_bytes_to_string_using_format( + bytes: Value, + format: Tagged, +) -> Result { + match bytes.value { + Primitive(Filesize(b)) => { + let byte = byte_unit::Byte::from_bytes(b as u128); + let value = match format.item().to_lowercase().as_str() { + "b" => Ok(UntaggedValue::string(b.to_formatted_string(&Locale::en))), + "kb" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::KB).to_string(), + )), + "kib" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::KiB).to_string(), + )), + "mb" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::MB).to_string(), + )), + "mib" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::MiB).to_string(), + )), + "gb" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::GB).to_string(), + )), + "gib" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::GiB).to_string(), + )), + "tb" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::TB).to_string(), + )), + "tib" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::TiB).to_string(), + )), + "pb" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::PB).to_string(), + )), + "pib" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::PiB).to_string(), + )), + "eb" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::EB).to_string(), + )), + "eib" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::EiB).to_string(), + )), + "zb" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::ZB).to_string(), + )), + "zib" => Ok(UntaggedValue::string( + byte.get_adjusted_unit(byte_unit::ByteUnit::ZiB).to_string(), + )), + _ => Err(ShellError::labeled_error( + format!("Invalid format code: {:}", format.item()), + "invalid format", + format.tag(), + )), + }; + match value { + Ok(b) => Ok(Value { value: b, ..bytes }), + Err(e) => Err(e), + } + } + _ => Err(ShellError::labeled_error( + "the data in this row is not of the type filesize", + "invalid row type", + bytes.tag(), + )), + } +} + +#[cfg(test)] +mod tests { + use super::FileSize; + use super::ShellError; + + #[test] + fn examples_work_as_expected() -> Result<(), ShellError> { + use crate::examples::test as test_examples; + + Ok(test_examples(FileSize {})?) + } +} diff --git a/crates/nu-cli/src/commands/format/mod.rs b/crates/nu-cli/src/commands/format/mod.rs new file mode 100644 index 0000000000..cd8267069c --- /dev/null +++ b/crates/nu-cli/src/commands/format/mod.rs @@ -0,0 +1,5 @@ +pub mod command; +pub mod format_filesize; + +pub use command::Format; +pub use format_filesize::FileSize; diff --git a/crates/nu-cli/tests/commands/format.rs b/crates/nu-cli/tests/commands/format.rs index d827781fd8..eee38afce2 100644 --- a/crates/nu-cli/tests/commands/format.rs +++ b/crates/nu-cli/tests/commands/format.rs @@ -1,3 +1,5 @@ +use nu_test_support::fs::Stub::EmptyFile; +use nu_test_support::playground::Playground; use nu_test_support::{nu, pipeline}; #[test] @@ -42,3 +44,26 @@ fn can_use_variables() { assert_eq!(actual.out, "nu is a new type of shell"); } + +#[test] +fn format_filesize_works() { + Playground::setup("format_filesize_test_1", |dirs, sandbox| { + sandbox.with_files(vec![ + EmptyFile("yehuda.txt"), + EmptyFile("jonathan.txt"), + EmptyFile("andres.txt"), + ]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls + | format filesize size KB + | get size + | first + "# + )); + + assert_eq!(actual.out, "0.01 KB"); + }) +}