add format filesize (#5498)

* add format filesize

* add comment

* add comment

* remove comment
This commit is contained in:
WindSoilder 2022-05-10 19:35:14 +08:00 committed by GitHub
parent e4959d2f9f
commit 8030f7e9f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 173 additions and 24 deletions

View File

@ -162,6 +162,7 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
Decode,
DetectColumns,
Format,
FileSize,
Parse,
Size,
Split,

View File

@ -0,0 +1,144 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
format_filesize, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature,
Span, SyntaxShape, Value,
};
use std::iter;
#[derive(Clone)]
pub struct FileSize;
impl Command for FileSize {
fn name(&self) -> &str {
"format filesize"
}
fn signature(&self) -> Signature {
Signature::build("format filesize")
.required(
"field",
SyntaxShape::String,
"the name of the column to update",
)
.required(
"format value",
SyntaxShape::String,
"the format into which convert the filesizes",
)
.category(Category::Strings)
}
fn usage(&self) -> &str {
"Converts a column of filesizes to some specified format"
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let field = call.req::<Value>(engine_state, stack, 0)?.as_string()?;
let format_value = call
.req::<Value>(engine_state, stack, 1)?
.as_string()?
.to_ascii_lowercase();
let span = call.head;
let data_as_value = input.into_value(span);
// Something need to consider:
// 1. what if input data type is not table? For now just output nothing.
// 2. what if value is not a FileSize type? For now just return nothing too for the value.
match data_as_value {
Value::List { vals, span } => format_impl(vals, field, format_value, span),
_ => Ok(Value::Nothing { span }.into_pipeline_data()),
}
}
fn examples(&self) -> Vec<Example> {
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,
},
]
}
}
fn format_impl(
vals: Vec<Value>,
field: String,
format_value: String,
input_span: Span,
) -> Result<PipelineData, ShellError> {
let records: Vec<Value> = vals
.into_iter()
.map(|rec| {
let record_span = rec.span();
match rec {
Value::Record { cols, vals, span } => {
let mut new_cols = vec![];
let mut new_vals = vec![];
for (c, v) in iter::zip(cols, vals) {
// find column to format, try format the value.
if c == field {
new_vals.push(format_value_impl(v, &format_value, span));
} else {
new_vals.push(v);
}
new_cols.push(c);
}
Value::Record {
cols: new_cols,
vals: new_vals,
span,
}
}
_ => Value::Nothing {
span: match record_span {
Ok(s) => s,
Err(_) => input_span,
},
},
}
})
.collect();
Ok(Value::List {
vals: records,
span: input_span,
}
.into_pipeline_data())
}
fn format_value_impl(val: Value, format_value: &str, span: Span) -> Value {
match val {
Value::Filesize { val, span } => Value::String {
// don't need to concern about metric, we just format units by what user input.
val: format_filesize(val, format_value, false),
span,
},
_ => Value::Nothing { span },
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(FileSize)
}
}

View File

@ -1,3 +1,5 @@
pub mod command;
mod filesize;
pub use self::filesize::FileSize;
pub use command::Format;

View File

@ -46,8 +46,6 @@ fn can_use_variables() {
assert_eq!(actual.out, "nu is a new type of shell");
}
// FIXME: jt: needs more work
#[ignore]
#[test]
fn format_filesize_works() {
Playground::setup("format_filesize_test_1", |dirs, sandbox| {
@ -71,8 +69,6 @@ fn format_filesize_works() {
})
}
// FIXME: jt: needs more work
#[ignore]
#[test]
fn format_filesize_works_with_nonempty_files() {
Playground::setup(

View File

@ -458,7 +458,7 @@ impl Value {
Value::Bool { val, .. } => val.to_string(),
Value::Int { val, .. } => val.to_string(),
Value::Float { val, .. } => val.to_string(),
Value::Filesize { val, .. } => format_filesize(*val, config),
Value::Filesize { val, .. } => format_filesize_from_conf(*val, config),
Value::Duration { val, .. } => format_duration(*val),
Value::Date { val, .. } => format!("{} ({})", val.to_rfc2822(), HumanTime::from(*val)),
Value::Range { val, .. } => {
@ -499,7 +499,7 @@ impl Value {
Value::Bool { val, .. } => val.to_string(),
Value::Int { val, .. } => val.to_string(),
Value::Float { val, .. } => val.to_string(),
Value::Filesize { val, .. } => format_filesize(*val, config),
Value::Filesize { val, .. } => format_filesize_from_conf(*val, config),
Value::Duration { val, .. } => format_duration(*val),
Value::Date { val, .. } => HumanTime::from(*val).to_string(),
Value::Range { val, .. } => {
@ -547,7 +547,7 @@ impl Value {
Value::Bool { val, .. } => val.to_string(),
Value::Int { val, .. } => val.to_string(),
Value::Float { val, .. } => val.to_string(),
Value::Filesize { val, .. } => format_filesize(*val, config),
Value::Filesize { val, .. } => format_filesize_from_conf(*val, config),
Value::Duration { val, .. } => format_duration(*val),
Value::Date { val, .. } => format!("{:?}", val),
Value::Range { val, .. } => {
@ -2325,14 +2325,24 @@ pub fn format_duration(duration: i64) -> String {
)
}
fn format_filesize(num_bytes: i64, config: &Config) -> String {
fn format_filesize_from_conf(num_bytes: i64, config: &Config) -> String {
// We need to take into account config.filesize_metric so, if someone asks for KB
// filesize_metric is true, return KiB
format_filesize(
num_bytes,
config.filesize_format.as_str(),
config.filesize_metric,
)
}
pub fn format_filesize(num_bytes: i64, format_value: &str, filesize_metric: bool) -> String {
// Allow the user to specify how they want their numbers formatted
let filesize_format_var = get_config_filesize_format(config);
let filesize_format_var = get_filesize_format(format_value, filesize_metric);
let byte = byte_unit::Byte::from_bytes(num_bytes as u128);
let adj_byte =
if filesize_format_var.0 == byte_unit::ByteUnit::B && filesize_format_var.1 == "auto" {
byte.get_appropriate_unit(!config.filesize_metric)
byte.get_appropriate_unit(!filesize_metric)
} else {
byte.get_adjusted_unit(filesize_format_var.0)
};
@ -2371,13 +2381,11 @@ fn format_filesize(num_bytes: i64, config: &Config) -> String {
}
}
fn get_config_filesize_format(config: &Config) -> (ByteUnit, &str) {
// We need to take into account config.filesize_metric so, if someone asks for KB
// filesize_metric is true, return KiB
let filesize_format = match config.filesize_format.as_str() {
fn get_filesize_format(format_value: &str, filesize_metric: bool) -> (ByteUnit, &str) {
match format_value {
"b" => (byte_unit::ByteUnit::B, ""),
"kb" => {
if config.filesize_metric {
if filesize_metric {
(byte_unit::ByteUnit::KiB, "")
} else {
(byte_unit::ByteUnit::KB, "")
@ -2385,7 +2393,7 @@ fn get_config_filesize_format(config: &Config) -> (ByteUnit, &str) {
}
"kib" => (byte_unit::ByteUnit::KiB, ""),
"mb" => {
if config.filesize_metric {
if filesize_metric {
(byte_unit::ByteUnit::MiB, "")
} else {
(byte_unit::ByteUnit::MB, "")
@ -2393,7 +2401,7 @@ fn get_config_filesize_format(config: &Config) -> (ByteUnit, &str) {
}
"mib" => (byte_unit::ByteUnit::MiB, ""),
"gb" => {
if config.filesize_metric {
if filesize_metric {
(byte_unit::ByteUnit::GiB, "")
} else {
(byte_unit::ByteUnit::GB, "")
@ -2401,7 +2409,7 @@ fn get_config_filesize_format(config: &Config) -> (ByteUnit, &str) {
}
"gib" => (byte_unit::ByteUnit::GiB, ""),
"tb" => {
if config.filesize_metric {
if filesize_metric {
(byte_unit::ByteUnit::TiB, "")
} else {
(byte_unit::ByteUnit::TB, "")
@ -2409,7 +2417,7 @@ fn get_config_filesize_format(config: &Config) -> (ByteUnit, &str) {
}
"tib" => (byte_unit::ByteUnit::TiB, ""),
"pb" => {
if config.filesize_metric {
if filesize_metric {
(byte_unit::ByteUnit::PiB, "")
} else {
(byte_unit::ByteUnit::PB, "")
@ -2417,7 +2425,7 @@ fn get_config_filesize_format(config: &Config) -> (ByteUnit, &str) {
}
"pib" => (byte_unit::ByteUnit::PiB, ""),
"eb" => {
if config.filesize_metric {
if filesize_metric {
(byte_unit::ByteUnit::EiB, "")
} else {
(byte_unit::ByteUnit::EB, "")
@ -2425,7 +2433,7 @@ fn get_config_filesize_format(config: &Config) -> (ByteUnit, &str) {
}
"eib" => (byte_unit::ByteUnit::EiB, ""),
"zb" => {
if config.filesize_metric {
if filesize_metric {
(byte_unit::ByteUnit::ZiB, "")
} else {
(byte_unit::ByteUnit::ZB, "")
@ -2433,9 +2441,7 @@ fn get_config_filesize_format(config: &Config) -> (ByteUnit, &str) {
}
"zib" => (byte_unit::ByteUnit::ZiB, ""),
_ => (byte_unit::ByteUnit::B, "auto"),
};
filesize_format
}
}
#[cfg(test)]