mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-12-28 10:40:48 +00:00
Encapsulate tree depth
It only really gets used for zeroes and having one added to it.
This commit is contained in:
parent
8453f45f99
commit
c0a2cf50af
@ -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"),
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.resize(params.depth.0 + 1, TreePart::Edge);
|
||||||
self.stack[params.depth] = if params.last { TreePart::Corner } else { 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
|
// Ignore the first element here to prevent a 'zeroth level' from
|
||||||
// a tree view for multiple directories, we don’t want there to be a
|
// appearing before the very first directory. This level would
|
||||||
// ‘zeroth level’ connecting the initial directories. Otherwise, not
|
// join unrelated directories without connecting to anything:
|
||||||
// only are unrelated directories seemingly connected to each other,
|
//
|
||||||
// but the tree part of the first row doesn’t connect 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(params(0, true)), &[]);
|
||||||
assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]);
|
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(params(0, true)), &[]);
|
||||||
assert_eq!(tt.new_row(TreeParams::new(1, false)), &[ TreePart::Edge ]);
|
assert_eq!(tt.new_row(params(1, false)), &[ TreePart::Edge ]);
|
||||||
assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]);
|
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(params(0, false)), &[]);
|
||||||
assert_eq!(tt.new_row(TreeParams::new(1, false)), &[ TreePart::Edge ]);
|
assert_eq!(tt.new_row(params(1, false)), &[ TreePart::Edge ]);
|
||||||
assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]);
|
assert_eq!(tt.new_row(params(1, true)), &[ TreePart::Corner ]);
|
||||||
|
|
||||||
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(params(1, false)), &[ TreePart::Edge ]);
|
||||||
assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]);
|
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(params(1, false)), &[ TreePart::Edge ]);
|
||||||
assert_eq!(tt.new_row(TreeParams::new(2, false)), &[ TreePart::Line, TreePart::Edge ]);
|
assert_eq!(tt.new_row(params(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(2, true)), &[ TreePart::Line, TreePart::Corner ]);
|
||||||
|
|
||||||
assert_eq!(tt.new_row(TreeParams::new(1, true)), &[ TreePart::Corner ]);
|
assert_eq!(tt.new_row(params(1, true)), &[ TreePart::Corner ]);
|
||||||
assert_eq!(tt.new_row(TreeParams::new(2, false)), &[ TreePart::Blank, TreePart::Edge ]);
|
assert_eq!(tt.new_row(params(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(2, true)), &[ TreePart::Blank, TreePart::Corner ]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user