Przeglądaj źródła

Encapsulate tree depth

It only really gets used for zeroes and having one added to it.
Benjamin Sago 8 lat temu
rodzic
commit
c0a2cf50af
3 zmienionych plików z 61 dodań i 49 usunięć
  1. 11 11
      src/output/details.rs
  2. 2 2
      src/output/grid_details.rs
  3. 48 36
      src/output/tree.rs

+ 11 - 11
src/output/details.rs

@@ -70,7 +70,7 @@ use options::{FileFilter, RecurseOptions};
 use output::colours::Colours;
 use output::colours::Colours;
 use output::column::Columns;
 use output::column::Columns;
 use output::cell::TextCell;
 use output::cell::TextCell;
-use output::tree::{TreeTrunk, TreeParams};
+use output::tree::{TreeTrunk, TreeParams, TreeDepth};
 use output::file_name::{FileName, LinkStyle, Classify};
 use output::file_name::{FileName, LinkStyle, Classify};
 use output::table::{Table, Environment, Row as TableRow};
 use output::table::{Table, Environment, Row as TableRow};
 
 
@@ -153,14 +153,14 @@ impl<'a> Render<'a> {
             // This is weird, but I can't find a way around it:
             // This is weird, but I can't find a way around it:
             // https://internals.rust-lang.org/t/should-option-mut-t-implement-copy/3715/6
             // https://internals.rust-lang.org/t/should-option-mut-t-implement-copy/3715/6
             let mut table = Some(table);
             let mut table = Some(table);
-            self.add_files_to_table(&mut table, &mut rows, &self.files, 0);
+            self.add_files_to_table(&mut table, &mut rows, &self.files, TreeDepth(0));
 
 
             for row in self.iterate_with_table(table.unwrap(), rows) {
             for row in self.iterate_with_table(table.unwrap(), rows) {
                 writeln!(w, "{}", row.strings())?
                 writeln!(w, "{}", row.strings())?
             }
             }
         }
         }
         else {
         else {
-            self.add_files_to_table(&mut None, &mut rows, &self.files, 0);
+            self.add_files_to_table(&mut None, &mut rows, &self.files, TreeDepth(0));
 
 
             for row in self.iterate(rows) {
             for row in self.iterate(rows) {
                 writeln!(w, "{}", row.strings())?
                 writeln!(w, "{}", row.strings())?
@@ -172,7 +172,7 @@ impl<'a> Render<'a> {
 
 
     /// Adds files to the table, possibly recursively. This is easily
     /// Adds files to the table, possibly recursively. This is easily
     /// parallelisable, and uses a pool of threads.
     /// parallelisable, and uses a pool of threads.
-    fn add_files_to_table<'dir>(&self, table: &mut Option<Table<'a>>, rows: &mut Vec<Row>, src: &Vec<File<'dir>>, depth: usize) {
+    fn add_files_to_table<'dir>(&self, table: &mut Option<Table<'a>>, rows: &mut Vec<Row>, src: &Vec<File<'dir>>, depth: TreeDepth) {
         use num_cpus;
         use num_cpus;
         use scoped_threadpool::Pool;
         use scoped_threadpool::Pool;
         use std::sync::{Arc, Mutex};
         use std::sync::{Arc, Mutex};
@@ -208,7 +208,7 @@ impl<'a> Render<'a> {
                     let mut dir = None;
                     let mut dir = None;
 
 
                     if let Some(r) = self.recurse {
                     if let Some(r) = self.recurse {
-                        if file.is_directory() && r.tree && !r.is_too_deep(depth) {
+                        if file.is_directory() && r.tree && !r.is_too_deep(depth.0) {
                             if let Ok(d) = file.to_dir(false) {
                             if let Ok(d) = file.to_dir(false) {
                                 dir = Some(d);
                                 dir = Some(d);
                             }
                             }
@@ -252,33 +252,33 @@ impl<'a> Render<'a> {
 
 
                 if !files.is_empty() {
                 if !files.is_empty() {
                     for xattr in egg.xattrs {
                     for xattr in egg.xattrs {
-                        rows.push(self.render_xattr(xattr, TreeParams::new(depth + 1, false)));
+                        rows.push(self.render_xattr(xattr, TreeParams::new(depth.deeper(), false)));
                     }
                     }
 
 
                     for (error, path) in errors {
                     for (error, path) in errors {
-                        rows.push(self.render_error(&error, TreeParams::new(depth + 1, false), path));
+                        rows.push(self.render_error(&error, TreeParams::new(depth.deeper(), false), path));
                     }
                     }
 
 
-                    self.add_files_to_table(table, rows, &files, depth + 1);
+                    self.add_files_to_table(table, rows, &files, depth.deeper());
                     continue;
                     continue;
                 }
                 }
             }
             }
 
 
             let count = egg.xattrs.len();
             let count = egg.xattrs.len();
             for (index, xattr) in egg.xattrs.into_iter().enumerate() {
             for (index, xattr) in egg.xattrs.into_iter().enumerate() {
-                rows.push(self.render_xattr(xattr, TreeParams::new(depth + 1, errors.is_empty() && index == count - 1)));
+                rows.push(self.render_xattr(xattr, TreeParams::new(depth.deeper(), errors.is_empty() && index == count - 1)));
             }
             }
 
 
             let count = errors.len();
             let count = errors.len();
             for (index, (error, path)) in errors.into_iter().enumerate() {
             for (index, (error, path)) in errors.into_iter().enumerate() {
-                rows.push(self.render_error(&error, TreeParams::new(depth + 1, index == count - 1), path));
+                rows.push(self.render_error(&error, TreeParams::new(depth.deeper(), index == count - 1), path));
             }
             }
         }
         }
     }
     }
 
 
     pub fn render_header(&self, header: TableRow) -> Row {
     pub fn render_header(&self, header: TableRow) -> Row {
         Row {
         Row {
-            tree:     TreeParams::new(0, false),
+            tree:     TreeParams::new(TreeDepth(0), false),
             cells:    Some(header),
             cells:    Some(header),
             name:     TextCell::paint_str(self.colours.header, "Name"),
             name:     TextCell::paint_str(self.colours.header, "Name"),
         }
         }

+ 2 - 2
src/output/grid_details.rs

@@ -14,7 +14,7 @@ use output::details::{Options as DetailsOptions, Row as DetailsRow, Render as De
 use output::grid::Options as GridOptions;
 use output::grid::Options as GridOptions;
 use output::file_name::{FileName, LinkStyle, Classify};
 use output::file_name::{FileName, LinkStyle, Classify};
 use output::table::{Table, Environment, Row as TableRow};
 use output::table::{Table, Environment, Row as TableRow};
-use output::tree::TreeParams;
+use output::tree::{TreeParams, TreeDepth};
 
 
 
 
 pub struct Render<'a> {
 pub struct Render<'a> {
@@ -120,7 +120,7 @@ impl<'a> Render<'a> {
 
 
             let (ref mut table, ref mut rows) = tables[index];
             let (ref mut table, ref mut rows) = tables[index];
             table.add_widths(&row);
             table.add_widths(&row);
-            let details_row = drender.render_file(row, file_name.clone(), TreeParams::new(0, false));
+            let details_row = drender.render_file(row, file_name.clone(), TreeParams::new(TreeDepth(0), false));
             rows.push(details_row);
             rows.push(details_row);
         }
         }
 
 

+ 48 - 36
src/output/tree.rs

@@ -88,12 +88,15 @@ pub struct TreeParams {
 
 
     /// How many directories deep into the tree structure this is. Directories
     /// How many directories deep into the tree structure this is. Directories
     /// on top have depth 0.
     /// on top have depth 0.
-    depth: usize,
+    depth: TreeDepth,
 
 
     /// Whether this is the last entry in the directory.
     /// Whether this is the last entry in the directory.
     last: bool,
     last: bool,
 }
 }
 
 
+#[derive(Debug, Copy, Clone)]
+pub struct TreeDepth(pub usize);
+
 impl TreeTrunk {
 impl TreeTrunk {
 
 
     /// Calculates the tree parts for an entry at the given depth and
     /// Calculates the tree parts for an entry at the given depth and
@@ -108,40 +111,45 @@ impl TreeTrunk {
         // If this isn’t our first iteration, then update the tree parts thus
         // If this isn’t our first iteration, then update the tree parts thus
         // far to account for there being another row after it.
         // far to account for there being another row after it.
         if let Some(last) = self.last_params {
         if let Some(last) = self.last_params {
-            self.stack[last.depth] = if last.last { TreePart::Blank } else { TreePart::Line };
+            self.stack[last.depth.0] = if last.last { TreePart::Blank } else { TreePart::Line };
         }
         }
 
 
         // Make sure the stack has enough space, then add or modify another
         // Make sure the stack has enough space, then add or modify another
         // part into it.
         // part into it.
-        self.stack.resize(params.depth + 1, TreePart::Edge);
-        self.stack[params.depth] = if params.last { TreePart::Corner } else { TreePart::Edge };
+        self.stack.resize(params.depth.0 + 1, TreePart::Edge);
+        self.stack[params.depth.0] = if params.last { TreePart::Corner } else { TreePart::Edge };
         self.last_params = Some(params);
         self.last_params = Some(params);
 
 
         // Return the tree parts as a slice of the stack.
         // Return the tree parts as a slice of the stack.
         //
         //
-        // Ignoring the first component is specific to exa: when a user prints
-        // a tree view for multiple directories, we don’t want there to be a
-        // ‘zeroth level’ connecting the initial directories. Otherwise, not
-        // only are unrelated directories seemingly connected to each other,
-        // but the tree part of the first row doesn’t connect to anything:
+        // Ignore the first element here to prevent a 'zeroth level' from
+        // appearing before the very first directory. This level would
+        // join unrelated directories without connecting to anything:
+        //
+        //     with [0..]        with [1..]
+        //     ==========        ==========
+        //      ├── folder        folder
+        //      │  └── file       └── file
+        //      └── folder        folder
+        //         └── file       └──file
         //
         //
-        // with [0..]             with [1..]
-        // ==========             ==========
-        // ├──folder              folder
-        // │  └──file             └──file
-        // └──folder              folder
-        //    └──file             └──file
         &self.stack[1..]
         &self.stack[1..]
     }
     }
 }
 }
 
 
 impl TreeParams {
 impl TreeParams {
-    pub fn new(depth: usize, last: bool) -> TreeParams {
+    pub fn new(depth: TreeDepth, last: bool) -> TreeParams {
         TreeParams { depth, last }
         TreeParams { depth, last }
     }
     }
 
 
     pub fn is_zero(&self) -> bool {
     pub fn is_zero(&self) -> bool {
-        self.depth == 0
+        self.depth.0 == 0
+    }
+}
+
+impl TreeDepth {
+    pub fn deeper(self) -> TreeDepth {
+        TreeDepth(self.0 + 1)
     }
     }
 }
 }
 
 
@@ -150,50 +158,54 @@ impl TreeParams {
 mod test {
 mod test {
     use super::*;
     use super::*;
 
 
+    fn params(depth: usize, last: bool) -> TreeParams {
+        TreeParams::new(TreeDepth(depth), last)
+    }
+
     #[test]
     #[test]
     fn empty_at_first() {
     fn empty_at_first() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
-        assert_eq!(tt.new_row(TreeParams::new(0, true)), &[]);
+        assert_eq!(tt.new_row(params(0, true)), &[]);
     }
     }
 
 
     #[test]
     #[test]
     fn one_child() {
     fn one_child() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
-        assert_eq!(tt.new_row(TreeParams::new(0, true)), &[]);
-        assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]);
+        assert_eq!(tt.new_row(params(0, true)), &[]);
+        assert_eq!(tt.new_row(params(1, true)), &[ TreePart::Corner ]);
     }
     }
 
 
     #[test]
     #[test]
     fn two_children() {
     fn two_children() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
-        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 ]);
+        assert_eq!(tt.new_row(params(0, true)),  &[]);
+        assert_eq!(tt.new_row(params(1, false)), &[ TreePart::Edge ]);
+        assert_eq!(tt.new_row(params(1, true)),  &[ TreePart::Corner ]);
     }
     }
 
 
     #[test]
     #[test]
     fn two_times_two_children() {
     fn two_times_two_children() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
-        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(params(0, false)), &[]);
+        assert_eq!(tt.new_row(params(1, false)), &[ TreePart::Edge ]);
+        assert_eq!(tt.new_row(params(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 ]);
+        assert_eq!(tt.new_row(params(0, true)),  &[]);
+        assert_eq!(tt.new_row(params(1, false)), &[ TreePart::Edge ]);
+        assert_eq!(tt.new_row(params(1, true)),  &[ TreePart::Corner ]);
     }
     }
 
 
     #[test]
     #[test]
     fn two_times_two_nested_children() {
     fn two_times_two_nested_children() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
-        assert_eq!(tt.new_row(TreeParams::new(0, true)), &[]);
+        assert_eq!(tt.new_row(params(0, true)), &[]);
 
 
-        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(params(1, false)), &[ TreePart::Edge ]);
+        assert_eq!(tt.new_row(params(2, false)), &[ TreePart::Line, TreePart::Edge ]);
+        assert_eq!(tt.new_row(params(2, true)),  &[ TreePart::Line, 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 ]);
+        assert_eq!(tt.new_row(params(1, true)),  &[ TreePart::Corner ]);
+        assert_eq!(tt.new_row(params(2, false)), &[ TreePart::Blank, TreePart::Edge ]);
+        assert_eq!(tt.new_row(params(2, true)),  &[ TreePart::Blank, TreePart::Corner ]);
     }
     }
 }
 }