diff options
author | Ben S <ogham@bsago.me> | 2015-02-26 07:18:08 +0000 |
---|---|---|
committer | Ben S <ogham@bsago.me> | 2015-02-26 07:18:08 +0000 |
commit | 134f9fc252aff5dcea95af5ad8fee4d9d30d696e (patch) | |
tree | d2a2cb05f81084f85168e910cab596211f6fafcf /src/output | |
parent | 3e6cce5b5c9f43f713a2f50632045fb8d1d546f7 (diff) |
Refactor details view
Move most of the heavy lifting into a Table struct, which doesn't govern how the resulting table is *created*, only how it's *displayed*.
Diffstat (limited to 'src/output')
-rw-r--r-- | src/output/details.rs | 182 |
1 files changed, 118 insertions, 64 deletions
diff --git a/src/output/details.rs b/src/output/details.rs index 76df7bc..77cec8c 100644 --- a/src/output/details.rs +++ b/src/output/details.rs @@ -18,7 +18,6 @@ pub struct Details { } impl Details { - pub fn view(&self, dir: Option<&Dir>, files: &[File]) { // The output gets formatted into columns, which looks nicer. To // do this, we have to write the results into a table, instead of @@ -26,47 +25,120 @@ impl Details { // width of each column based on the length of the results and // padding the fields during output. - let columns = self.columns.for_dir(dir); - let locale = UserLocale::new(); - let mut cache = OSUsers::empty_cache(); - let mut table = Vec::new(); - self.get_files(&columns[..], &mut cache, &locale, &mut table, files, 0); - - if self.header { - let row = Row { - depth: 0, - cells: columns.iter().map(|c| Cell::paint(Plain.underline(), c.header())).collect(), - name: Plain.underline().paint("Name").to_string(), - last: false, - attrs: Vec::new(), - children: false, - }; - - table.insert(0, row); + // Almost all the heavy lifting is done in a Table object, which + // automatically calculates the width of each column and the + // appropriate padding. + let mut table = Table::with_columns(self.columns.for_dir(dir)); + if self.header { table.add_header() } + + self.add_files_to_table(&mut table, files, 0); + table.print_table(self.xattr, self.recurse.is_some()); + } + + /// Adds files to the table - recursively, if the `recurse` option + /// is present. + fn add_files_to_table(&self, table: &mut Table, src: &[File], depth: usize) { + for (index, file) in src.iter().enumerate() { + table.add_row(file, depth, index == src.len() - 1); + + if let Some(r) = self.recurse { + if r.tree == false || r.is_too_deep(depth) { + continue; + } + + if let Some(ref dir) = file.this { + let mut files = dir.files(true); + self.filter.transform_files(&mut files); + self.add_files_to_table(table, &files, depth + 1); + } + } } + } +} - let column_widths: Vec<usize> = range(0, columns.len()) - .map(|n| table.iter().map(|row| row.cells[n].length).max().unwrap_or(0)) - .collect(); +struct Row { + pub depth: usize, + pub cells: Vec<Cell>, + pub name: String, + pub last: bool, + pub attrs: Vec<Attribute>, + pub children: bool, +} + +type ColumnInfo = (usize, Alignment); + +struct Table { + columns: Vec<Column>, + users: OSUsers, + locale: UserLocale, + rows: Vec<Row>, +} + +impl Table { + fn with_columns(columns: Vec<Column>) -> Table { + Table { + columns: columns, + users: OSUsers::empty_cache(), + locale: UserLocale::new(), + rows: Vec::new(), + } + } + fn add_header(&mut self) { + let row = Row { + depth: 0, + cells: self.columns.iter().map(|c| Cell::paint(Plain.underline(), c.header())).collect(), + name: Plain.underline().paint("Name").to_string(), + last: false, + attrs: Vec::new(), + children: false, + }; + + self.rows.push(row); + } + + fn cells_for_file(&mut self, file: &File) -> Vec<Cell> { + self.columns.clone().iter() + .map(|c| file.display(c, &mut self.users, &self.locale)) + .collect() + } + + fn add_row(&mut self, file: &File, depth: usize, last: bool) { + let row = Row { + depth: depth, + cells: self.cells_for_file(file), + name: file.file_name_view(), + last: last, + attrs: file.xattrs.clone(), + children: file.this.is_some(), + }; + + self.rows.push(row) + } + + fn print_table(self, xattr: bool, show_children: bool) { let mut stack = Vec::new(); - for row in table { - for (num, column) in columns.iter().enumerate() { - let padding = column_widths[num] - row.cells[num].length; - print!("{} ", column.alignment().pad_string(&row.cells[num].text, padding)); + let column_widths: Vec<usize> = range(0, self.columns.len()) + .map(|n| self.rows.iter().map(|row| row.cells[n].length).max().unwrap_or(0)) + .collect(); + + for row in self.rows.iter() { + for (n, width) in column_widths.iter().enumerate() { + let padding = width - row.cells[n].length; + print!("{} ", self.columns[n].alignment().pad_string(&row.cells[n].text, padding)); } - if self.recurse.is_some() { - stack.resize(row.depth + 1, "├──"); - stack[row.depth] = if row.last { "└──" } else { "├──" }; + if show_children { + stack.resize(row.depth + 1, TreePart::Edge); + stack[row.depth] = if row.last { TreePart::Corner } else { TreePart::Edge }; for i in 1 .. row.depth + 1 { - print!("{}", GREY.paint(stack[i])); + print!("{}", GREY.paint(stack[i].ascii_art())); } if row.children { - stack[row.depth] = if row.last { " " } else { "│ " }; + stack[row.depth] = if row.last { TreePart::Blank } else { TreePart::Line }; } if row.depth != 0 { @@ -76,7 +148,7 @@ impl Details { print!("{}\n", row.name); - if self.xattr { + if xattr { let width = row.attrs.iter().map(|a| a.name().len()).max().unwrap_or(0); for attr in row.attrs.iter() { let name = attr.name(); @@ -88,45 +160,27 @@ impl Details { } } } +} - fn get_files(&self, columns: &[Column], cache: &mut OSUsers, locale: &UserLocale, dest: &mut Vec<Row>, src: &[File], depth: usize) { - for (index, file) in src.iter().enumerate() { - - let row = Row { - depth: depth, - cells: columns.iter().map(|c| file.display(c, cache, locale)).collect(), - name: file.file_name_view(), - last: index == src.len() - 1, - attrs: file.xattrs.clone(), - children: file.this.is_some(), - }; - - dest.push(row); - - if let Some(r) = self.recurse { - if r.tree == false || r.is_too_deep(depth) { - continue; - } +#[derive(PartialEq, Debug, Clone)] +enum TreePart { + Edge, + Corner, + Blank, + Line, +} - if let Some(ref dir) = file.this { - let mut files = dir.files(true); - self.filter.transform_files(&mut files); - self.get_files(columns, cache, locale, dest, &files, depth + 1); - } - } +impl TreePart { + fn ascii_art(&self) -> &'static str { + match *self { + TreePart::Edge => "├──", + TreePart::Line => "│ ", + TreePart::Corner => "└──", + TreePart::Blank => " ", } } } -struct Row { - pub depth: usize, - pub cells: Vec<Cell>, - pub name: String, - pub last: bool, - pub attrs: Vec<Attribute>, - pub children: bool, -} - pub struct UserLocale { pub time: locale::Time, pub numeric: locale::Numeric, |