diff --git a/src/output/details.rs b/src/output/details.rs index 8961f8e..48fc17b 100644 --- a/src/output/details.rs +++ b/src/output/details.rs @@ -70,7 +70,7 @@ use options::{FileFilter, RecurseOptions}; use output::colours::Colours; use output::column::Columns; use output::cell::TextCell; -use output::tree::TreeTrunk; +use output::tree::{TreeTrunk, TreeParams}; use output::file_name::{FileName, LinkStyle, Classify}; use output::table::{Table, Environment, Row as TableRow}; @@ -233,10 +233,9 @@ impl<'a> Render<'a> { } let row = Row { - depth: depth, - cells: egg.table_row, - name: FileName::new(&egg.file, LinkStyle::FullLinkPaths, self.classify, self.colours).paint().promote(), - last: index == num_eggs - 1, + tree: TreeParams::new(depth, index == num_eggs - 1), + cells: egg.table_row, + name: FileName::new(&egg.file, LinkStyle::FullLinkPaths, self.classify, self.colours).paint().promote(), }; rows.push(row); @@ -253,11 +252,11 @@ impl<'a> Render<'a> { if !files.is_empty() { for xattr in egg.xattrs { - rows.push(self.render_xattr(xattr, depth + 1, false)); + rows.push(self.render_xattr(xattr, TreeParams::new(depth + 1, false))); } for (error, path) in errors { - rows.push(self.render_error(&error, depth + 1, false, path)); + rows.push(self.render_error(&error, TreeParams::new(depth + 1, false), path)); } self.add_files_to_table(table, rows, &files, depth + 1); @@ -267,55 +266,41 @@ impl<'a> Render<'a> { let count = egg.xattrs.len(); for (index, xattr) in egg.xattrs.into_iter().enumerate() { - rows.push(self.render_xattr(xattr, depth + 1, errors.is_empty() && index == count - 1)); + rows.push(self.render_xattr(xattr, TreeParams::new(depth + 1, errors.is_empty() && index == count - 1))); } let count = errors.len(); for (index, (error, path)) in errors.into_iter().enumerate() { - rows.push(self.render_error(&error, depth + 1, index == count - 1, path)); + rows.push(self.render_error(&error, TreeParams::new(depth + 1, index == count - 1), path)); } } } pub fn render_header(&self, header: TableRow) -> Row { Row { - depth: 0, + tree: TreeParams::new(0, false), cells: Some(header), name: TextCell::paint_str(self.colours.header, "Name"), - last: false, } } - fn render_error(&self, error: &IOError, depth: usize, last: bool, path: Option) -> Row { + fn render_error(&self, error: &IOError, tree: TreeParams, path: Option) -> Row { let error_message = match path { Some(path) => format!("<{}: {}>", path.display(), error), None => format!("<{}>", error), }; - Row { - depth: depth, - cells: None, - name: TextCell::paint(self.colours.broken_arrow, error_message), - last: last, - } + let name = TextCell::paint(self.colours.broken_arrow, error_message); + Row { cells: None, name, tree } } - fn render_xattr(&self, xattr: Attribute, depth: usize, last: bool) -> Row { - Row { - depth: depth, - cells: None, - name: TextCell::paint(self.colours.perms.attribute, format!("{} (len {})", xattr.name, xattr.size)), - last: last, - } + fn render_xattr(&self, xattr: Attribute, tree: TreeParams) -> Row { + let name = TextCell::paint(self.colours.perms.attribute, format!("{} (len {})", xattr.name, xattr.size)); + Row { cells: None, name, tree } } - pub fn render_file(&self, cells: TableRow, name_cell: TextCell, depth: usize, last: bool) -> Row { - Row { - depth: depth, - cells: Some(cells), - name: name_cell, - last: last, - } + pub fn render_file(&self, cells: TableRow, name: TextCell, tree: TreeParams) -> Row { + Row { cells: Some(cells), name, tree } } pub fn iterate_with_table(&'a self, table: Table<'a>, rows: Vec) -> TableIter<'a> { @@ -360,13 +345,13 @@ impl<'a> Iterator for TableIter<'a> { cell }; - for tree_part in self.tree_trunk.new_row(row.depth, row.last) { + for tree_part in self.tree_trunk.new_row(row.tree) { cell.push(self.colours.punctuation.paint(tree_part.ascii_art()), 4); } // If any tree characters have been printed, then add an extra // space, which makes the output look much better. - if row.depth != 0 { + if !row.tree.is_zero() { cell.add_spaces(1); } @@ -390,13 +375,8 @@ pub struct Row { /// from the other cells, as it never requires padding. pub name: TextCell, - /// How many directories deep into the tree structure this is. Directories - /// on top have depth 0. - pub depth: usize, - - /// Whether this is the last entry in the directory. This flag is used - /// when calculating the tree view. - pub last: bool, + /// Information used to determine which symbols to display in a tree. + pub tree: TreeParams, } @@ -414,13 +394,13 @@ impl<'a> Iterator for Iter<'a> { self.inner.next().map(|row| { let mut cell = TextCell::default(); - for tree_part in self.tree_trunk.new_row(row.depth, row.last) { + for tree_part in self.tree_trunk.new_row(row.tree) { cell.push(self.colours.punctuation.paint(tree_part.ascii_art()), 4); } // If any tree characters have been printed, then add an extra // space, which makes the output look much better. - if row.depth != 0 { + if !row.tree.is_zero() { cell.add_spaces(1); } diff --git a/src/output/grid_details.rs b/src/output/grid_details.rs index 63df709..01ed1d9 100644 --- a/src/output/grid_details.rs +++ b/src/output/grid_details.rs @@ -14,6 +14,7 @@ use output::details::{Options as DetailsOptions, Row as DetailsRow, Render as De use output::grid::Options as GridOptions; use output::file_name::{FileName, LinkStyle, Classify}; use output::table::{Table, Environment, Row as TableRow}; +use output::tree::TreeParams; pub struct Render<'a> { @@ -119,7 +120,7 @@ impl<'a> Render<'a> { let (ref mut table, ref mut rows) = tables[index]; table.add_widths(&row); - let details_row = drender.render_file(row, file_name.clone(), 0, false); + let details_row = drender.render_file(row, file_name.clone(), TreeParams::new(0, false)); rows.push(details_row); } diff --git a/src/output/tree.rs b/src/output/tree.rs index db01cff..b996ad9 100644 --- a/src/output/tree.rs +++ b/src/output/tree.rs @@ -38,6 +38,7 @@ //! successfully `stat`ted, we don’t know how many files are going to exist in //! each directory) + #[derive(PartialEq, Debug, Clone)] pub enum TreePart { @@ -79,7 +80,18 @@ pub struct TreeTrunk { stack: Vec, /// A tuple for the last ‘depth’ and ‘last’ parameters that are passed in. - last_params: Option<(usize, bool)>, + last_params: Option, +} + +#[derive(Debug, Copy, Clone)] +pub struct TreeParams { + + /// How many directories deep into the tree structure this is. Directories + /// on top have depth 0. + depth: usize, + + /// Whether this is the last entry in the directory. + last: bool, } impl TreeTrunk { @@ -91,19 +103,19 @@ impl TreeTrunk { /// /// This takes a `&mut self` because the results of each file are stored /// and used in future rows. - pub fn new_row(&mut self, depth: usize, last: bool) -> &[TreePart] { + pub fn new_row(&mut self, params: TreeParams) -> &[TreePart] { // If this isn’t our first iteration, then update the tree parts thus // far to account for there being another row after it. - if let Some((last_depth, last_last)) = self.last_params { - self.stack[last_depth] = if last_last { TreePart::Blank } else { TreePart::Line }; + if let Some(last) = self.last_params { + self.stack[last.depth] = if last.last { TreePart::Blank } else { TreePart::Line }; } // Make sure the stack has enough space, then add or modify another // part into it. - self.stack.resize(depth + 1, TreePart::Edge); - self.stack[depth] = if last { TreePart::Corner } else { TreePart::Edge }; - self.last_params = Some((depth, last)); + self.stack.resize(params.depth + 1, TreePart::Edge); + self.stack[params.depth] = if params.last { TreePart::Corner } else { TreePart::Edge }; + self.last_params = Some(params); // Return the tree parts as a slice of the stack. // @@ -123,6 +135,16 @@ impl TreeTrunk { } } +impl TreeParams { + pub fn new(depth: usize, last: bool) -> TreeParams { + TreeParams { depth, last } + } + + pub fn is_zero(&self) -> bool { + self.depth == 0 + } +} + #[cfg(test)] mod test { @@ -131,47 +153,47 @@ mod test { #[test] fn empty_at_first() { let mut tt = TreeTrunk::default(); - assert_eq!(tt.new_row(0, true), &[]); + assert_eq!(tt.new_row(TreeParams::new(0, true)), &[]); } #[test] fn one_child() { let mut tt = TreeTrunk::default(); - assert_eq!(tt.new_row(0, true), &[]); - assert_eq!(tt.new_row(1, true), &[ TreePart::Corner ]); + assert_eq!(tt.new_row(TreeParams::new(0, true)), &[]); + assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]); } #[test] fn two_children() { let mut tt = TreeTrunk::default(); - assert_eq!(tt.new_row(0, true), &[]); - assert_eq!(tt.new_row(1, false), &[ TreePart::Edge ]); - assert_eq!(tt.new_row(1, true), &[ TreePart::Corner ]); + assert_eq!(tt.new_row(TreeParams::new(0, true)), &[]); + assert_eq!(tt.new_row(TreeParams::new(1, false)), &[ TreePart::Edge ]); + assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]); } #[test] fn two_times_two_children() { let mut tt = TreeTrunk::default(); - assert_eq!(tt.new_row(0, false), &[]); - assert_eq!(tt.new_row(1, false), &[ TreePart::Edge ]); - assert_eq!(tt.new_row(1, true), &[ TreePart::Corner ]); + assert_eq!(tt.new_row(TreeParams::new(0, false)), &[]); + assert_eq!(tt.new_row(TreeParams::new(1, false)), &[ TreePart::Edge ]); + assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]); - assert_eq!(tt.new_row(0, true), &[]); - assert_eq!(tt.new_row(1, false), &[ TreePart::Edge ]); - assert_eq!(tt.new_row(1, true), &[ TreePart::Corner ]); + assert_eq!(tt.new_row(TreeParams::new(0, true)), &[]); + assert_eq!(tt.new_row(TreeParams::new(1, false)), &[ TreePart::Edge ]); + assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]); } #[test] fn two_times_two_nested_children() { let mut tt = TreeTrunk::default(); - assert_eq!(tt.new_row(0, true), &[]); + assert_eq!(tt.new_row(TreeParams::new(0, true)), &[]); - assert_eq!(tt.new_row(1, false), &[ TreePart::Edge ]); - assert_eq!(tt.new_row(2, false), &[ TreePart::Line, TreePart::Edge ]); - assert_eq!(tt.new_row(2, true), &[ TreePart::Line, TreePart::Corner ]); + assert_eq!(tt.new_row(TreeParams::new(1, false)), &[ TreePart::Edge ]); + assert_eq!(tt.new_row(TreeParams::new(2, false)), &[ TreePart::Line, TreePart::Edge ]); + assert_eq!(tt.new_row(TreeParams::new(2, true)), &[ TreePart::Line, TreePart::Corner ]); - assert_eq!(tt.new_row(1, true), &[ TreePart::Corner ]); - assert_eq!(tt.new_row(2, false), &[ TreePart::Blank, TreePart::Edge ]); - assert_eq!(tt.new_row(2, true), &[ TreePart::Blank, TreePart::Corner ]); + assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]); + assert_eq!(tt.new_row(TreeParams::new(2, false)), &[ TreePart::Blank, TreePart::Edge ]); + assert_eq!(tt.new_row(TreeParams::new(2, true)), &[ TreePart::Blank, TreePart::Corner ]); } }