grid_details.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. use std::io::{Write, Result as IOResult};
  2. use std::sync::Arc;
  3. use ansi_term::ANSIStrings;
  4. use users::UsersCache;
  5. use term_grid as grid;
  6. use fs::{Dir, File};
  7. use fs::feature::xattr::FileAttributes;
  8. use output::cell::TextCell;
  9. use output::column::Column;
  10. use output::details::{Details, Table, Environment};
  11. use output::grid::Grid;
  12. #[derive(PartialEq, Debug, Clone)]
  13. pub struct GridDetails {
  14. pub grid: Grid,
  15. pub details: Details,
  16. }
  17. fn file_has_xattrs(file: &File) -> bool {
  18. match file.path.attributes() {
  19. Ok(attrs) => !attrs.is_empty(),
  20. Err(_) => false,
  21. }
  22. }
  23. impl GridDetails {
  24. pub fn view<W>(&self, dir: Option<&Dir>, files: Vec<File>, w: &mut W) -> IOResult<()>
  25. where W: Write {
  26. let columns_for_dir = match self.details.columns {
  27. Some(cols) => cols.for_dir(dir),
  28. None => Vec::new(),
  29. };
  30. let env = Arc::new(Environment::default());
  31. let (cells, file_names) = {
  32. let first_table = self.make_table(env.clone(), &*columns_for_dir);
  33. let cells = files.iter()
  34. .map(|file| first_table.cells_for_file(file, file_has_xattrs(file)))
  35. .collect::<Vec<_>>();
  36. let file_names = files.into_iter()
  37. .map(|file| first_table.filename(file, false).promote())
  38. .collect::<Vec<_>>();
  39. (cells, file_names)
  40. };
  41. let mut last_working_table = self.make_grid(env.clone(), 1, &columns_for_dir, &file_names, cells.clone());
  42. for column_count in 2.. {
  43. let grid = self.make_grid(env.clone(), column_count, &columns_for_dir, &file_names, cells.clone());
  44. let the_grid_fits = {
  45. let d = grid.fit_into_columns(column_count);
  46. d.is_complete() && d.width() <= self.grid.console_width
  47. };
  48. if the_grid_fits {
  49. last_working_table = grid;
  50. }
  51. else {
  52. return write!(w, "{}", last_working_table.fit_into_columns(column_count - 1));
  53. }
  54. }
  55. Ok(())
  56. }
  57. fn make_table<'a>(&'a self, env: Arc<Environment<UsersCache>>, columns_for_dir: &'a [Column]) -> Table<UsersCache> {
  58. let mut table = Table {
  59. columns: columns_for_dir,
  60. opts: &self.details,
  61. env: env,
  62. rows: Vec::new(),
  63. };
  64. if self.details.header { table.add_header() }
  65. table
  66. }
  67. fn make_grid<'a>(&'a self, env: Arc<Environment<UsersCache>>, column_count: usize, columns_for_dir: &'a [Column], file_names: &[TextCell], cells: Vec<Vec<TextCell>>) -> grid::Grid {
  68. let mut tables = Vec::new();
  69. for _ in 0 .. column_count {
  70. tables.push(self.make_table(env.clone(), columns_for_dir));
  71. }
  72. let mut num_cells = cells.len();
  73. if self.details.header {
  74. num_cells += column_count;
  75. }
  76. let original_height = divide_rounding_up(cells.len(), column_count);
  77. let height = divide_rounding_up(num_cells, column_count);
  78. for (i, (file_name, row)) in file_names.iter().zip(cells.into_iter()).enumerate() {
  79. let index = if self.grid.across {
  80. i % column_count
  81. }
  82. else {
  83. i / original_height
  84. };
  85. tables[index].add_file_with_cells(row, file_name.clone(), 0, false);
  86. }
  87. let columns: Vec<_> = tables.into_iter().map(|t| t.print_table()).collect();
  88. let direction = if self.grid.across { grid::Direction::LeftToRight }
  89. else { grid::Direction::TopToBottom };
  90. let mut grid = grid::Grid::new(grid::GridOptions {
  91. direction: direction,
  92. filling: grid::Filling::Spaces(4),
  93. });
  94. if self.grid.across {
  95. for row in 0 .. height {
  96. for column in &columns {
  97. if row < column.len() {
  98. let cell = grid::Cell {
  99. contents: ANSIStrings(&column[row].contents).to_string(),
  100. width: *column[row].width,
  101. };
  102. grid.add(cell);
  103. }
  104. }
  105. }
  106. }
  107. else {
  108. for column in &columns {
  109. for cell in column.iter() {
  110. let cell = grid::Cell {
  111. contents: ANSIStrings(&cell.contents).to_string(),
  112. width: *cell.width,
  113. };
  114. grid.add(cell);
  115. }
  116. }
  117. }
  118. grid
  119. }
  120. }
  121. fn divide_rounding_up(a: usize, b: usize) -> usize {
  122. let mut result = a / b;
  123. if a % b != 0 { result += 1; }
  124. result
  125. }