2017-08-20 19:29:23 +00:00
|
|
|
use ansi_term::Style;
|
|
|
|
use locale::Numeric as NumericLocale;
|
2019-11-17 14:50:07 +00:00
|
|
|
use number_prefix::Prefix;
|
2017-08-20 19:29:23 +00:00
|
|
|
|
2018-12-07 23:43:31 +00:00
|
|
|
use crate::fs::fields as f;
|
|
|
|
use crate::output::cell::{TextCell, DisplayWidth};
|
|
|
|
use crate::output::table::SizeFormat;
|
2017-05-20 20:43:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
impl f::Size {
|
2020-10-10 14:30:19 +00:00
|
|
|
pub fn render<C: Colours>(self, colours: &C, size_format: SizeFormat, numerics: &NumericLocale) -> TextCell {
|
2020-10-10 01:14:35 +00:00
|
|
|
use number_prefix::NumberPrefix;
|
2017-05-20 20:43:04 +00:00
|
|
|
|
2020-10-10 14:30:19 +00:00
|
|
|
let size = match self {
|
2020-10-10 12:55:26 +00:00
|
|
|
Self::Some(s) => s,
|
|
|
|
Self::None => return TextCell::blank(colours.no_size()),
|
|
|
|
Self::DeviceIDs(ref ids) => return ids.render(colours),
|
2017-05-20 20:43:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let result = match size_format {
|
2019-04-17 05:54:06 +00:00
|
|
|
SizeFormat::DecimalBytes => NumberPrefix::decimal(size as f64),
|
|
|
|
SizeFormat::BinaryBytes => NumberPrefix::binary(size as f64),
|
2017-05-20 20:43:04 +00:00
|
|
|
SizeFormat::JustBytes => {
|
2020-10-10 18:49:46 +00:00
|
|
|
|
2019-11-17 14:50:07 +00:00
|
|
|
// Use the binary prefix to select a style.
|
|
|
|
let prefix = match NumberPrefix::binary(size as f64) {
|
2020-10-10 18:49:46 +00:00
|
|
|
NumberPrefix::Standalone(_) => None,
|
|
|
|
NumberPrefix::Prefixed(p, _) => Some(p),
|
2019-11-17 14:50:07 +00:00
|
|
|
};
|
2020-10-10 18:49:46 +00:00
|
|
|
|
2019-11-17 14:50:07 +00:00
|
|
|
// But format the number directly using the locale.
|
2017-05-20 20:43:04 +00:00
|
|
|
let string = numerics.format_int(size);
|
2020-10-10 18:49:46 +00:00
|
|
|
|
2019-11-17 14:50:07 +00:00
|
|
|
return TextCell::paint(colours.size(prefix), string);
|
2020-10-10 18:49:46 +00:00
|
|
|
}
|
2017-05-20 20:43:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let (prefix, n) = match result {
|
2020-10-10 18:49:46 +00:00
|
|
|
NumberPrefix::Standalone(b) => return TextCell::paint(colours.size(None), b.to_string()),
|
|
|
|
NumberPrefix::Prefixed(p, n) => (p, n),
|
2017-05-20 20:43:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let symbol = prefix.symbol();
|
2020-10-10 14:57:40 +00:00
|
|
|
let number = if n < 10_f64 { numerics.format_float(n, 1) }
|
|
|
|
else { numerics.format_int(n as isize) };
|
2017-05-20 20:43:04 +00:00
|
|
|
|
|
|
|
// The numbers and symbols are guaranteed to be written in ASCII, so
|
|
|
|
// we can skip the display width calculation.
|
|
|
|
let width = DisplayWidth::from(number.len() + symbol.len());
|
|
|
|
|
|
|
|
TextCell {
|
2018-06-19 12:58:03 +00:00
|
|
|
width,
|
2017-05-20 20:43:04 +00:00
|
|
|
contents: vec![
|
2019-11-17 14:50:07 +00:00
|
|
|
colours.size(Some(prefix)).paint(number),
|
|
|
|
colours.unit(Some(prefix)).paint(symbol),
|
2017-05-20 20:43:04 +00:00
|
|
|
].into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-20 19:29:23 +00:00
|
|
|
|
2017-05-20 20:55:18 +00:00
|
|
|
impl f::DeviceIDs {
|
2020-10-10 14:30:19 +00:00
|
|
|
fn render<C: Colours>(self, colours: &C) -> TextCell {
|
2017-05-20 20:55:18 +00:00
|
|
|
let major = self.major.to_string();
|
|
|
|
let minor = self.minor.to_string();
|
|
|
|
|
|
|
|
TextCell {
|
|
|
|
width: DisplayWidth::from(major.len() + 1 + minor.len()),
|
|
|
|
contents: vec![
|
2017-08-20 19:29:23 +00:00
|
|
|
colours.major().paint(major),
|
|
|
|
colours.comma().paint(","),
|
|
|
|
colours.minor().paint(minor),
|
2017-05-20 20:55:18 +00:00
|
|
|
].into(),
|
|
|
|
}
|
2017-05-20 20:43:04 +00:00
|
|
|
}
|
|
|
|
}
|
2017-05-21 08:49:17 +00:00
|
|
|
|
2020-10-10 18:49:46 +00:00
|
|
|
|
2017-08-20 19:29:23 +00:00
|
|
|
pub trait Colours {
|
2019-11-17 14:50:07 +00:00
|
|
|
fn size(&self, prefix: Option<Prefix>) -> Style;
|
|
|
|
fn unit(&self, prefix: Option<Prefix>) -> Style;
|
2017-08-26 22:53:47 +00:00
|
|
|
fn no_size(&self) -> Style;
|
2017-08-20 19:29:23 +00:00
|
|
|
|
2017-08-26 22:53:47 +00:00
|
|
|
fn major(&self) -> Style;
|
|
|
|
fn comma(&self) -> Style;
|
|
|
|
fn minor(&self) -> Style;
|
2017-08-20 19:29:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-21 08:49:17 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
pub mod test {
|
2017-08-26 22:53:47 +00:00
|
|
|
use super::Colours;
|
2018-12-07 23:43:31 +00:00
|
|
|
use crate::output::cell::{TextCell, DisplayWidth};
|
|
|
|
use crate::output::table::SizeFormat;
|
|
|
|
use crate::fs::fields as f;
|
2017-05-21 08:49:17 +00:00
|
|
|
|
2017-08-20 19:29:23 +00:00
|
|
|
use locale::Numeric as NumericLocale;
|
2017-05-21 08:49:17 +00:00
|
|
|
use ansi_term::Colour::*;
|
2017-08-20 19:29:23 +00:00
|
|
|
use ansi_term::Style;
|
2019-11-17 14:50:07 +00:00
|
|
|
use number_prefix::Prefix;
|
2017-08-26 22:53:47 +00:00
|
|
|
|
|
|
|
|
2017-08-20 19:29:23 +00:00
|
|
|
struct TestColours;
|
2017-08-26 22:53:47 +00:00
|
|
|
|
2017-08-20 19:29:23 +00:00
|
|
|
impl Colours for TestColours {
|
2019-11-17 14:50:07 +00:00
|
|
|
fn size(&self, _prefix: Option<Prefix>) -> Style { Fixed(66).normal() }
|
|
|
|
fn unit(&self, _prefix: Option<Prefix>) -> Style { Fixed(77).bold() }
|
2017-08-26 22:53:47 +00:00
|
|
|
fn no_size(&self) -> Style { Black.italic() }
|
|
|
|
|
|
|
|
fn major(&self) -> Style { Blue.on(Red) }
|
|
|
|
fn comma(&self) -> Style { Green.italic() }
|
|
|
|
fn minor(&self) -> Style { Cyan.on(Yellow) }
|
2017-08-20 19:29:23 +00:00
|
|
|
}
|
2017-05-21 08:49:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn directory() {
|
|
|
|
let directory = f::Size::None;
|
2017-08-20 19:29:23 +00:00
|
|
|
let expected = TextCell::blank(Black.italic());
|
|
|
|
assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
|
2017-05-21 08:49:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn file_decimal() {
|
|
|
|
let directory = f::Size::Some(2_100_000);
|
|
|
|
let expected = TextCell {
|
|
|
|
width: DisplayWidth::from(4),
|
|
|
|
contents: vec![
|
2017-08-20 19:29:23 +00:00
|
|
|
Fixed(66).paint("2.1"),
|
|
|
|
Fixed(77).bold().paint("M"),
|
2017-05-21 08:49:17 +00:00
|
|
|
].into(),
|
|
|
|
};
|
|
|
|
|
2017-08-20 19:29:23 +00:00
|
|
|
assert_eq!(expected, directory.render(&TestColours, SizeFormat::DecimalBytes, &NumericLocale::english()))
|
2017-05-21 08:49:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn file_binary() {
|
|
|
|
let directory = f::Size::Some(1_048_576);
|
|
|
|
let expected = TextCell {
|
|
|
|
width: DisplayWidth::from(5),
|
|
|
|
contents: vec![
|
2017-08-20 19:29:23 +00:00
|
|
|
Fixed(66).paint("1.0"),
|
|
|
|
Fixed(77).bold().paint("Mi"),
|
2017-05-21 08:49:17 +00:00
|
|
|
].into(),
|
|
|
|
};
|
|
|
|
|
2017-08-20 19:29:23 +00:00
|
|
|
assert_eq!(expected, directory.render(&TestColours, SizeFormat::BinaryBytes, &NumericLocale::english()))
|
2017-05-21 08:49:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn file_bytes() {
|
|
|
|
let directory = f::Size::Some(1048576);
|
|
|
|
let expected = TextCell {
|
|
|
|
width: DisplayWidth::from(9),
|
|
|
|
contents: vec![
|
2017-08-20 19:29:23 +00:00
|
|
|
Fixed(66).paint("1,048,576"),
|
2017-05-21 08:49:17 +00:00
|
|
|
].into(),
|
|
|
|
};
|
|
|
|
|
2017-08-20 19:29:23 +00:00
|
|
|
assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
|
2017-05-21 08:49:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn device_ids() {
|
|
|
|
let directory = f::Size::DeviceIDs(f::DeviceIDs { major: 10, minor: 80 });
|
|
|
|
let expected = TextCell {
|
|
|
|
width: DisplayWidth::from(5),
|
|
|
|
contents: vec![
|
|
|
|
Blue.on(Red).paint("10"),
|
|
|
|
Green.italic().paint(","),
|
|
|
|
Cyan.on(Yellow).paint("80"),
|
|
|
|
].into(),
|
|
|
|
};
|
|
|
|
|
2017-08-20 19:29:23 +00:00
|
|
|
assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
|
2017-05-21 08:49:17 +00:00
|
|
|
}
|
|
|
|
}
|