details.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. use column::{Column, Cell};
  2. use dir::Dir;
  3. use file::{File, GREY};
  4. use options::{Columns, FileFilter};
  5. use users::OSUsers;
  6. use locale;
  7. use ansi_term::Style::Plain;
  8. #[derive(PartialEq, Debug, Copy)]
  9. pub struct Details {
  10. pub columns: Columns,
  11. pub header: bool,
  12. pub tree: bool,
  13. pub filter: FileFilter,
  14. }
  15. impl Details {
  16. pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
  17. // The output gets formatted into columns, which looks nicer. To
  18. // do this, we have to write the results into a table, instead of
  19. // displaying each file immediately, then calculating the maximum
  20. // width of each column based on the length of the results and
  21. // padding the fields during output.
  22. let columns = self.columns.for_dir(dir);
  23. let locale = UserLocale::new();
  24. let mut cache = OSUsers::empty_cache();
  25. let mut table = Vec::new();
  26. self.get_files(&columns[], &mut cache, &locale, &mut table, files, 0);
  27. if self.header {
  28. let row = Row {
  29. depth: 0,
  30. cells: columns.iter().map(|c| Cell::paint(Plain.underline(), c.header())).collect(),
  31. name: Plain.underline().paint("Name").to_string(),
  32. last: false,
  33. children: false,
  34. };
  35. table.insert(0, row);
  36. }
  37. let column_widths: Vec<usize> = range(0, columns.len())
  38. .map(|n| table.iter().map(|row| row.cells[n].length).max().unwrap_or(0))
  39. .collect();
  40. let mut stack = Vec::new();
  41. for row in table {
  42. for (num, column) in columns.iter().enumerate() {
  43. let padding = column_widths[num] - row.cells[num].length;
  44. print!("{} ", column.alignment().pad_string(&row.cells[num].text, padding));
  45. }
  46. if self.tree {
  47. stack.resize(row.depth + 1, "├──");
  48. stack[row.depth] = if row.last { "└──" } else { "├──" };
  49. for i in 1 .. row.depth + 1 {
  50. print!("{}", GREY.paint(stack[i]));
  51. }
  52. if row.children {
  53. stack[row.depth] = if row.last { " " } else { "│ " };
  54. }
  55. if row.depth != 0 {
  56. print!(" ");
  57. }
  58. }
  59. print!("{}\n", row.name);
  60. }
  61. }
  62. fn get_files(&self, columns: &[Column], cache: &mut OSUsers, locale: &UserLocale, dest: &mut Vec<Row>, src: &[File], depth: usize) {
  63. for (index, file) in src.iter().enumerate() {
  64. let row = Row {
  65. depth: depth,
  66. cells: columns.iter().map(|c| file.display(c, cache, locale)).collect(),
  67. name: file.file_name_view(),
  68. last: index == src.len() - 1,
  69. children: file.this.is_some(),
  70. };
  71. dest.push(row);
  72. if self.tree {
  73. if let Some(ref dir) = file.this {
  74. let mut files = dir.files(true);
  75. self.filter.transform_files(&mut files);
  76. self.get_files(columns, cache, locale, dest, files.as_slice(), depth + 1);
  77. }
  78. }
  79. }
  80. }
  81. }
  82. struct Row {
  83. pub depth: usize,
  84. pub cells: Vec<Cell>,
  85. pub name: String,
  86. pub last: bool,
  87. pub children: bool,
  88. }
  89. pub struct UserLocale {
  90. pub time: locale::Time,
  91. pub numeric: locale::Numeric,
  92. }
  93. impl UserLocale {
  94. pub fn new() -> UserLocale {
  95. UserLocale {
  96. time: locale::Time::load_user_locale().unwrap_or_else(|_| locale::Time::default()),
  97. numeric: locale::Numeric::load_user_locale().unwrap_or_else(|_| locale::Numeric::default()),
  98. }
  99. }
  100. pub fn default() -> UserLocale {
  101. UserLocale {
  102. time: locale::Time::default(),
  103. numeric: locale::Numeric::default(),
  104. }
  105. }
  106. }