size.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. use ansi_term::Style;
  2. use locale::Numeric as NumericLocale;
  3. use fs::fields as f;
  4. use output::cell::{TextCell, DisplayWidth};
  5. use output::table::SizeFormat;
  6. impl f::Size {
  7. pub fn render<C: Colours>(&self, colours: &C, size_format: SizeFormat, numerics: &NumericLocale) -> TextCell {
  8. use number_prefix::{binary_prefix, decimal_prefix};
  9. use number_prefix::{Prefixed, Standalone, PrefixNames};
  10. let size = match *self {
  11. f::Size::Some(s) => s,
  12. f::Size::None => return TextCell::blank(colours.no_size()),
  13. f::Size::DeviceIDs(ref ids) => return ids.render(colours),
  14. };
  15. let result = match size_format {
  16. SizeFormat::DecimalBytes => decimal_prefix(size as f64),
  17. SizeFormat::BinaryBytes => binary_prefix(size as f64),
  18. SizeFormat::JustBytes => {
  19. let string = numerics.format_int(size);
  20. return TextCell::paint(colours.size(size), string);
  21. },
  22. };
  23. let (prefix, n) = match result {
  24. Standalone(b) => return TextCell::paint(colours.size(b as u64), b.to_string()),
  25. Prefixed(p, n) => (p, n)
  26. };
  27. let symbol = prefix.symbol();
  28. let number = if n < 10f64 { numerics.format_float(n, 1) }
  29. else { numerics.format_int(n as isize) };
  30. // The numbers and symbols are guaranteed to be written in ASCII, so
  31. // we can skip the display width calculation.
  32. let width = DisplayWidth::from(number.len() + symbol.len());
  33. TextCell {
  34. width,
  35. contents: vec![
  36. colours.size(size).paint(number),
  37. colours.unit().paint(symbol),
  38. ].into(),
  39. }
  40. }
  41. }
  42. impl f::DeviceIDs {
  43. fn render<C: Colours>(&self, colours: &C) -> TextCell {
  44. let major = self.major.to_string();
  45. let minor = self.minor.to_string();
  46. TextCell {
  47. width: DisplayWidth::from(major.len() + 1 + minor.len()),
  48. contents: vec![
  49. colours.major().paint(major),
  50. colours.comma().paint(","),
  51. colours.minor().paint(minor),
  52. ].into(),
  53. }
  54. }
  55. }
  56. pub trait Colours {
  57. fn size(&self, size: u64) -> Style;
  58. fn unit(&self) -> Style;
  59. fn no_size(&self) -> Style;
  60. fn major(&self) -> Style;
  61. fn comma(&self) -> Style;
  62. fn minor(&self) -> Style;
  63. }
  64. #[cfg(test)]
  65. pub mod test {
  66. use super::Colours;
  67. use output::cell::{TextCell, DisplayWidth};
  68. use output::table::SizeFormat;
  69. use fs::fields as f;
  70. use locale::Numeric as NumericLocale;
  71. use ansi_term::Colour::*;
  72. use ansi_term::Style;
  73. struct TestColours;
  74. impl Colours for TestColours {
  75. fn size(&self, _size: u64) -> Style { Fixed(66).normal() }
  76. fn unit(&self) -> Style { Fixed(77).bold() }
  77. fn no_size(&self) -> Style { Black.italic() }
  78. fn major(&self) -> Style { Blue.on(Red) }
  79. fn comma(&self) -> Style { Green.italic() }
  80. fn minor(&self) -> Style { Cyan.on(Yellow) }
  81. }
  82. #[test]
  83. fn directory() {
  84. let directory = f::Size::None;
  85. let expected = TextCell::blank(Black.italic());
  86. assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
  87. }
  88. #[test]
  89. fn file_decimal() {
  90. let directory = f::Size::Some(2_100_000);
  91. let expected = TextCell {
  92. width: DisplayWidth::from(4),
  93. contents: vec![
  94. Fixed(66).paint("2.1"),
  95. Fixed(77).bold().paint("M"),
  96. ].into(),
  97. };
  98. assert_eq!(expected, directory.render(&TestColours, SizeFormat::DecimalBytes, &NumericLocale::english()))
  99. }
  100. #[test]
  101. fn file_binary() {
  102. let directory = f::Size::Some(1_048_576);
  103. let expected = TextCell {
  104. width: DisplayWidth::from(5),
  105. contents: vec![
  106. Fixed(66).paint("1.0"),
  107. Fixed(77).bold().paint("Mi"),
  108. ].into(),
  109. };
  110. assert_eq!(expected, directory.render(&TestColours, SizeFormat::BinaryBytes, &NumericLocale::english()))
  111. }
  112. #[test]
  113. fn file_bytes() {
  114. let directory = f::Size::Some(1048576);
  115. let expected = TextCell {
  116. width: DisplayWidth::from(9),
  117. contents: vec![
  118. Fixed(66).paint("1,048,576"),
  119. ].into(),
  120. };
  121. assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
  122. }
  123. #[test]
  124. fn device_ids() {
  125. let directory = f::Size::DeviceIDs(f::DeviceIDs { major: 10, minor: 80 });
  126. let expected = TextCell {
  127. width: DisplayWidth::from(5),
  128. contents: vec![
  129. Blue.on(Red).paint("10"),
  130. Green.italic().paint(","),
  131. Cyan.on(Yellow).paint("80"),
  132. ].into(),
  133. };
  134. assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
  135. }
  136. }