2015-09-03 17:48:53 +00:00
|
|
|
|
//! The **Details** output view displays each file as a row in a table.
|
|
|
|
|
//!
|
|
|
|
|
//! It's used in the following situations:
|
|
|
|
|
//!
|
|
|
|
|
//! - Most commonly, when using the `--long` command-line argument to display the
|
|
|
|
|
//! details of each file, which requires using a table view to hold all the data;
|
|
|
|
|
//! - When using the `--tree` argument, which uses the same table view to display
|
|
|
|
|
//! each file on its own line, with the table providing the tree characters;
|
|
|
|
|
//! - When using both the `--long` and `--grid` arguments, which constructs a
|
|
|
|
|
//! series of tables to fit all the data on the screen.
|
|
|
|
|
//!
|
|
|
|
|
//! You will probably recognise it from the `ls --long` command. It looks like
|
|
|
|
|
//! this:
|
|
|
|
|
//!
|
2016-04-19 06:48:41 +00:00
|
|
|
|
//! ```text
|
2015-09-03 17:48:53 +00:00
|
|
|
|
//! .rw-r--r-- 9.6k ben 29 Jun 16:16 Cargo.lock
|
|
|
|
|
//! .rw-r--r-- 547 ben 23 Jun 10:54 Cargo.toml
|
|
|
|
|
//! .rw-r--r-- 1.1k ben 23 Nov 2014 LICENCE
|
|
|
|
|
//! .rw-r--r-- 2.5k ben 21 May 14:38 README.md
|
|
|
|
|
//! .rw-r--r-- 382k ben 8 Jun 21:00 screenshot.png
|
|
|
|
|
//! drwxr-xr-x - ben 29 Jun 14:50 src
|
|
|
|
|
//! drwxr-xr-x - ben 28 Jun 19:53 target
|
2016-04-19 06:48:41 +00:00
|
|
|
|
//! ```
|
2015-09-03 17:48:53 +00:00
|
|
|
|
//!
|
|
|
|
|
//! The table is constructed by creating a `Table` value, which produces a `Row`
|
|
|
|
|
//! value for each file. These rows can contain a vector of `Cell`s, or they can
|
|
|
|
|
//! contain depth information for the tree view, or both. These are described
|
|
|
|
|
//! below.
|
|
|
|
|
//!
|
|
|
|
|
//!
|
|
|
|
|
//! ## Constructing Detail Views
|
|
|
|
|
//!
|
|
|
|
|
//! When using the `--long` command-line argument, the details of each file are
|
|
|
|
|
//! displayed next to its name.
|
|
|
|
|
//!
|
|
|
|
|
//! The table holds a vector of all the column types. For each file and column, a
|
|
|
|
|
//! `Cell` value containing the ANSI-coloured text and Unicode width of each cell
|
|
|
|
|
//! is generated, with the row and column determined by indexing into both arrays.
|
|
|
|
|
//!
|
|
|
|
|
//! The column types vector does not actually include the filename. This is
|
|
|
|
|
//! because the filename is always the rightmost field, and as such, it does not
|
|
|
|
|
//! need to have its width queried or be padded with spaces.
|
|
|
|
|
//!
|
|
|
|
|
//! To illustrate the above:
|
|
|
|
|
//!
|
2016-04-19 06:48:41 +00:00
|
|
|
|
//! ```text
|
2015-09-03 17:48:53 +00:00
|
|
|
|
//! ┌─────────────────────────────────────────────────────────────────────────┐
|
|
|
|
|
//! │ columns: [ Permissions, Size, User, Date(Modified) ] │
|
|
|
|
|
//! ├─────────────────────────────────────────────────────────────────────────┤
|
|
|
|
|
//! │ rows: cells: filename: │
|
|
|
|
|
//! │ row 1: [ ".rw-r--r--", "9.6k", "ben", "29 Jun 16:16" ] Cargo.lock │
|
|
|
|
|
//! │ row 2: [ ".rw-r--r--", "547", "ben", "23 Jun 10:54" ] Cargo.toml │
|
|
|
|
|
//! │ row 3: [ "drwxr-xr-x", "-", "ben", "29 Jun 14:50" ] src │
|
|
|
|
|
//! │ row 4: [ "drwxr-xr-x", "-", "ben", "28 Jun 19:53" ] target │
|
|
|
|
|
//! └─────────────────────────────────────────────────────────────────────────┘
|
2016-04-19 06:48:41 +00:00
|
|
|
|
//! ```
|
2015-09-03 17:48:53 +00:00
|
|
|
|
//!
|
|
|
|
|
//! Each column in the table needs to be resized to fit its widest argument. This
|
|
|
|
|
//! means that we must wait until every row has been added to the table before it
|
|
|
|
|
//! can be displayed, in order to make sure that every column is wide enough.
|
|
|
|
|
|
|
|
|
|
|
2016-04-18 17:39:32 +00:00
|
|
|
|
use std::io::{Write, Error as IOError, Result as IOResult};
|
2015-08-26 10:36:10 +00:00
|
|
|
|
use std::path::PathBuf;
|
2017-07-02 00:02:17 +00:00
|
|
|
|
use std::vec::IntoIter as VecIntoIter;
|
2015-02-05 14:39:56 +00:00
|
|
|
|
|
2017-08-20 20:39:52 +00:00
|
|
|
|
use ansi_term::Style;
|
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
|
use fs::{Dir, File};
|
2017-07-24 07:34:50 +00:00
|
|
|
|
use fs::dir_action::RecurseOptions;
|
|
|
|
|
use fs::filter::FileFilter;
|
2017-09-28 08:09:57 +00:00
|
|
|
|
use fs::feature::ignore::IgnoreCache;
|
2017-09-01 18:13:47 +00:00
|
|
|
|
use fs::feature::git::GitCache;
|
2016-04-16 17:59:25 +00:00
|
|
|
|
use fs::feature::xattr::{Attribute, FileAttributes};
|
2017-08-26 20:40:37 +00:00
|
|
|
|
use style::Colours;
|
2017-07-02 00:02:17 +00:00
|
|
|
|
use output::cell::TextCell;
|
2017-07-03 21:46:40 +00:00
|
|
|
|
use output::tree::{TreeTrunk, TreeParams, TreeDepth};
|
2017-07-08 11:24:22 +00:00
|
|
|
|
use output::file_name::FileStyle;
|
2017-07-05 20:01:01 +00:00
|
|
|
|
use output::table::{Table, Options as TableOptions, Row as TableRow};
|
2018-02-14 01:53:53 +00:00
|
|
|
|
use scoped_threadpool::Pool;
|
2015-06-04 14:15:39 +00:00
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
|
|
2015-02-26 08:27:29 +00:00
|
|
|
|
/// With the **Details** view, the output gets formatted into columns, with
|
|
|
|
|
/// each `Column` object showing some piece of information about the file,
|
|
|
|
|
/// such as its size, or its permissions.
|
|
|
|
|
///
|
|
|
|
|
/// To do this, the results have to be written to a table, instead of
|
|
|
|
|
/// displaying each file immediately. Then, the width of each column can be
|
|
|
|
|
/// calculated based on the individual results, and the fields are padded
|
|
|
|
|
/// during output.
|
|
|
|
|
///
|
|
|
|
|
/// Almost all the heavy lifting is done in a Table object, which handles the
|
|
|
|
|
/// columns for each row.
|
2017-07-05 19:16:04 +00:00
|
|
|
|
#[derive(Debug)]
|
2017-06-25 23:53:48 +00:00
|
|
|
|
pub struct Options {
|
2015-02-26 08:27:29 +00:00
|
|
|
|
|
2017-07-05 19:16:04 +00:00
|
|
|
|
/// Options specific to drawing a table.
|
|
|
|
|
///
|
|
|
|
|
/// Directories themselves can pick which columns are *added* to this
|
|
|
|
|
/// list, such as the Git column.
|
2017-07-05 20:01:01 +00:00
|
|
|
|
pub table: Option<TableOptions>,
|
2015-02-26 08:27:29 +00:00
|
|
|
|
|
|
|
|
|
/// Whether to show a header line or not.
|
|
|
|
|
pub header: bool,
|
|
|
|
|
|
|
|
|
|
/// Whether to show each file's extended attributes.
|
2015-02-22 12:55:13 +00:00
|
|
|
|
pub xattr: bool,
|
2015-02-05 14:39:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-10 19:02:20 +00:00
|
|
|
|
|
2015-09-03 17:48:53 +00:00
|
|
|
|
|
2017-06-25 23:53:48 +00:00
|
|
|
|
pub struct Render<'a> {
|
|
|
|
|
pub dir: Option<&'a Dir>,
|
|
|
|
|
pub files: Vec<File<'a>>,
|
|
|
|
|
pub colours: &'a Colours,
|
2017-07-08 11:11:11 +00:00
|
|
|
|
pub style: &'a FileStyle,
|
2017-06-25 23:53:48 +00:00
|
|
|
|
pub opts: &'a Options,
|
2017-06-26 07:28:32 +00:00
|
|
|
|
|
|
|
|
|
/// Whether to recurse through directories with a tree view, and if so,
|
|
|
|
|
/// which options to use. This field is only relevant here if the `tree`
|
|
|
|
|
/// field of the RecurseOptions is `true`.
|
|
|
|
|
pub recurse: Option<RecurseOptions>,
|
|
|
|
|
|
|
|
|
|
/// How to sort and filter the files after getting their details.
|
|
|
|
|
pub filter: &'a FileFilter,
|
2017-06-25 23:53:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-03 17:48:53 +00:00
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
|
struct Egg<'a> {
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
table_row: Option<TableRow>,
|
2017-07-02 00:02:17 +00:00
|
|
|
|
xattrs: Vec<Attribute>,
|
|
|
|
|
errors: Vec<(IOError, Option<PathBuf>)>,
|
|
|
|
|
dir: Option<Dir>,
|
|
|
|
|
file: &'a File<'a>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> AsRef<File<'a>> for Egg<'a> {
|
|
|
|
|
fn as_ref(&self) -> &File<'a> {
|
|
|
|
|
self.file
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> Render<'a> {
|
2017-09-28 08:09:57 +00:00
|
|
|
|
pub fn render<W: Write>(self, mut git: Option<&'a GitCache>, ignore: Option<&'a IgnoreCache>, w: &mut W) -> IOResult<()> {
|
2018-02-14 01:53:53 +00:00
|
|
|
|
use num_cpus;
|
|
|
|
|
let mut pool = Pool::new(num_cpus::get() as u32);
|
2017-07-02 00:02:17 +00:00
|
|
|
|
let mut rows = Vec::new();
|
Use Mutex lock on only the users columns
This makes use of a change in the `users` crate to change which parts of exa's code are accessed under a `Mutex`. The change is that the methods on `Users` can now take just `&self`, instead of `&mut self`. This has a knock-on effect in exa, as many methods now don't need to take a mutable `&self`, meaning that the Mutex can be moved to only containing the users information instead of having to be queried for *every column*. This means that threading should now be a lot faster, as fewer parts have to be executed on a single thread.
The main change to facilitate this is that `Table`'s structure has changed: everything environmental that gets loaded at the beginning is now in an `Environment` struct, which can be mocked out if necessary, as one of `Table`'s fields. (They were kind of in a variety of places before.)
Casualties include having to make some of the test code more verbose, as it explicitly takes the columns and environment as references rather than values, and those both need to be put on the stack beforehand. Also, all the colours are now hidden behind an `opts` field, so a lot of the rendering code is more verbose too (but not greatly so).
2016-01-16 21:56:37 +00:00
|
|
|
|
|
2017-07-05 20:01:01 +00:00
|
|
|
|
if let Some(ref table) = self.opts.table {
|
2017-09-02 11:13:41 +00:00
|
|
|
|
match (git, self.dir) {
|
|
|
|
|
(Some(g), Some(d)) => if !g.has_anything_for(&d.path) { git = None },
|
|
|
|
|
(Some(g), None) => if !self.files.iter().any(|f| g.has_anything_for(&f.path)) { git = None },
|
|
|
|
|
(None, _) => {/* Keep Git how it is */},
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-01 21:52:13 +00:00
|
|
|
|
let mut table = Table::new(&table, git, &self.colours);
|
Use Mutex lock on only the users columns
This makes use of a change in the `users` crate to change which parts of exa's code are accessed under a `Mutex`. The change is that the methods on `Users` can now take just `&self`, instead of `&mut self`. This has a knock-on effect in exa, as many methods now don't need to take a mutable `&self`, meaning that the Mutex can be moved to only containing the users information instead of having to be queried for *every column*. This means that threading should now be a lot faster, as fewer parts have to be executed on a single thread.
The main change to facilitate this is that `Table`'s structure has changed: everything environmental that gets loaded at the beginning is now in an `Environment` struct, which can be mocked out if necessary, as one of `Table`'s fields. (They were kind of in a variety of places before.)
Casualties include having to make some of the test code more verbose, as it explicitly takes the columns and environment as references rather than values, and those both need to be put on the stack beforehand. Also, all the colours are now hidden behind an `opts` field, so a lot of the rendering code is more verbose too (but not greatly so).
2016-01-16 21:56:37 +00:00
|
|
|
|
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
if self.opts.header {
|
|
|
|
|
let header = table.header_row();
|
2017-07-03 16:40:05 +00:00
|
|
|
|
table.add_widths(&header);
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
rows.push(self.render_header(header));
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-02 11:13:41 +00:00
|
|
|
|
// This is weird, but I can’t find a way around it:
|
2017-07-03 19:53:37 +00:00
|
|
|
|
// https://internals.rust-lang.org/t/should-option-mut-t-implement-copy/3715/6
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
let mut table = Some(table);
|
2018-02-14 01:53:53 +00:00
|
|
|
|
self.add_files_to_table(&mut pool, &mut table, &mut rows, &self.files, ignore, TreeDepth::root());
|
2015-02-26 07:18:08 +00:00
|
|
|
|
|
2017-07-03 19:12:32 +00:00
|
|
|
|
for row in self.iterate_with_table(table.unwrap(), rows) {
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
writeln!(w, "{}", row.strings())?
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2018-02-14 01:53:53 +00:00
|
|
|
|
self.add_files_to_table(&mut pool, &mut None, &mut rows, &self.files, ignore, TreeDepth::root());
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
|
2017-07-03 19:12:32 +00:00
|
|
|
|
for row in self.iterate(rows) {
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
writeln!(w, "{}", row.strings())?
|
|
|
|
|
}
|
2015-06-28 12:21:21 +00:00
|
|
|
|
}
|
2016-04-18 17:39:32 +00:00
|
|
|
|
|
|
|
|
|
Ok(())
|
2015-02-26 07:18:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-03 17:48:53 +00:00
|
|
|
|
/// Adds files to the table, possibly recursively. This is easily
|
|
|
|
|
/// parallelisable, and uses a pool of threads.
|
2018-02-14 01:53:53 +00:00
|
|
|
|
fn add_files_to_table<'dir, 'ig>(&self, pool: &mut Pool, table: &mut Option<Table<'a>>, rows: &mut Vec<Row>, src: &Vec<File<'dir>>, ignore: Option<&'ig IgnoreCache>, depth: TreeDepth) {
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
use std::sync::{Arc, Mutex};
|
2016-04-16 17:59:25 +00:00
|
|
|
|
use fs::feature::xattr;
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
|
|
|
|
|
let mut file_eggs = Vec::new();
|
|
|
|
|
|
|
|
|
|
pool.scoped(|scoped| {
|
|
|
|
|
let file_eggs = Arc::new(Mutex::new(&mut file_eggs));
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
let table = table.as_ref();
|
2015-08-25 14:04:15 +00:00
|
|
|
|
|
Replace Cells with growable TextCells
A recent change to ansi-term [1] means that `ANSIString`s can now hold either
owned *or* borrowed data (Rust calls this the Cow type). This means that we
can delay formatting ANSIStrings into ANSI-control-code-formatted strings
until it's absolutely necessary. The process for doing this was:
1. Replace the `Cell` type with a `TextCell` type that holds a vector of
`ANSIString` values instead of a formatted string. It still does the
width tracking.
2. Rework the details module's `render` functions to emit values of this
type.
3. Similarly, rework the functions that produce cells containing filenames
to use a `File` value's `name` field, which is an owned `String` that
can now be re-used.
4. Update the printing, formatting, and width-calculating code in the
details and grid-details views to produce a table by adding vectors
together instead of adding strings together, delaying the formatting as
long as it can.
This results in fewer allocations (as fewer `String` values are produced), and
makes the API tidier (as fewer `String` values are being passed around without
having their contents specified).
This also paves the way to Windows support, or at least support for
non-ANSI terminals: by delaying the time until strings are formatted,
it'll now be easier to change *how* they are formatted.
Casualties include:
- Bump to ansi_term v0.7.1, which impls `PartialEq` and `Debug` on
`ANSIString`.
- The grid_details and lines views now need to take a vector of files, rather
than a borrowed slice, so the filename cells produced now own the filename
strings that get taken from files.
- Fixed the signature of `File#link_target` to specify that the
file produced refers to the same directory, rather than some phantom
directory with the same lifetime as the file. (This was wrong from the
start, but it broke nothing until now)
References:
[1]: ansi-term@f6a6579ba8174de1cae64d181ec04af32ba2a4f0
2015-12-17 00:25:20 +00:00
|
|
|
|
for file in src {
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
let file_eggs = file_eggs.clone();
|
2015-08-26 10:36:10 +00:00
|
|
|
|
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
scoped.execute(move || {
|
|
|
|
|
let mut errors = Vec::new();
|
|
|
|
|
let mut xattrs = Vec::new();
|
2016-01-16 22:19:00 +00:00
|
|
|
|
|
2017-08-11 11:36:14 +00:00
|
|
|
|
// There are three “levels” of extended attribute support:
|
|
|
|
|
//
|
|
|
|
|
// 1. If we’re compiling without that feature, then
|
2017-09-13 19:45:41 +00:00
|
|
|
|
// exa pretends all files have no attributes.
|
|
|
|
|
// 2. If the feature is enabled and the --extended flag
|
|
|
|
|
// has been specified, then display an @ in the
|
|
|
|
|
// permissions column for files with attributes, the
|
|
|
|
|
// names of all attributes and their lengths, and any
|
|
|
|
|
// errors encountered when getting them.
|
|
|
|
|
// 3. If the --extended flag *hasn’t* been specified, then
|
|
|
|
|
// display the @, but don’t display anything else.
|
2017-08-11 11:36:14 +00:00
|
|
|
|
//
|
2017-09-13 19:45:41 +00:00
|
|
|
|
// For a while, exa took a stricter approach to (3):
|
|
|
|
|
// if an error occurred while checking a file’s xattrs to
|
|
|
|
|
// see if it should display the @, exa would display that
|
|
|
|
|
// error even though the attributes weren’t actually being
|
|
|
|
|
// shown! This was confusing, as users were being shown
|
|
|
|
|
// errors for something they didn’t explicitly ask for,
|
|
|
|
|
// and just cluttered up the output. So now errors aren’t
|
|
|
|
|
// printed unless the user passes --extended to signify
|
|
|
|
|
// that they want to see them.
|
2017-08-11 11:36:14 +00:00
|
|
|
|
|
2016-01-16 22:19:00 +00:00
|
|
|
|
if xattr::ENABLED {
|
|
|
|
|
match file.path.attributes() {
|
2017-08-19 10:03:53 +00:00
|
|
|
|
Ok(xs) => {
|
|
|
|
|
xattrs.extend(xs);
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
if self.opts.xattr {
|
|
|
|
|
errors.push((e, None));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
error!("Error looking up xattr for {:?}: {:#?}", file.path, e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-16 22:19:00 +00:00
|
|
|
|
}
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
let table_row = table.as_ref().map(|t| t.row_for_file(&file, !xattrs.is_empty()));
|
2015-09-03 17:48:53 +00:00
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
|
if !self.opts.xattr {
|
2016-01-16 22:19:00 +00:00
|
|
|
|
xattrs.clear();
|
|
|
|
|
}
|
|
|
|
|
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
let mut dir = None;
|
|
|
|
|
|
2017-06-26 07:28:32 +00:00
|
|
|
|
if let Some(r) = self.recurse {
|
2017-07-03 21:46:40 +00:00
|
|
|
|
if file.is_directory() && r.tree && !r.is_too_deep(depth.0) {
|
2017-09-01 18:13:47 +00:00
|
|
|
|
match file.to_dir() {
|
2017-07-04 16:48:30 +00:00
|
|
|
|
Ok(d) => { dir = Some(d); },
|
|
|
|
|
Err(e) => { errors.push((e, None)) },
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
|
let egg = Egg { table_row, xattrs, errors, dir, file };
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
file_eggs.lock().unwrap().push(egg);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2017-06-26 07:28:32 +00:00
|
|
|
|
self.filter.sort_files(&mut file_eggs);
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
|
2017-07-04 07:29:36 +00:00
|
|
|
|
for (tree_params, egg) in depth.iterate_over(file_eggs.into_iter()) {
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
let mut files = Vec::new();
|
|
|
|
|
let mut errors = egg.errors;
|
Measure, rather than calculating, cell widths
exa deals with cells and widths a lot: the items in a grid need to be aligned according to their *contents’* widths, rather than the length of their strings, which often included ANSI escape characters. As an optimisation, it used to calculate this separately based on the filename, and dealing with any extra characters (such as the classify ones) in that function too.
Recently, though, file names have become a lot more complicated. Classification added zero to one extra characters, and now with escaped control characters in file names, it’s not so easy to calculate the display width of a filename.
This commit removes the function that calculated the width, in favour of building the output string (it’s going to be displayed anyway) and just getting the width of what it displays instead.
2017-05-01 13:11:16 +00:00
|
|
|
|
|
Only get an Env if one’s being used, also mutexes
This commit ties a table’s Environment to the fact that it contains columns.
Previously, the Details view would get its Environment, and then use those fields to actually display the details in the table: except for the case where we’re only displaying a tree, when it would just be ignored, instead.
This was caused by the “no columns” case using a Vec of no Columns behind the scenes, rather than disabling the table entirely; much like how a tap isn’t a zero-length swipe, the code should have been updated to reflect this. Now, the Environment is only created if it’s going to be used.
Also, fix a double-mutex-lock: the mutable Table had to be accessed under a lock, but the table contained a UsersCache, which *also* had to be accessed under a lock. This was changed so that the table is only updated *after* the threads have all been joined, so there’s no need for any lock at all. May fix #141, but not sure.
2017-07-03 16:04:37 +00:00
|
|
|
|
if let (Some(ref mut t), Some(ref row)) = (table.as_mut(), egg.table_row.as_ref()) {
|
|
|
|
|
t.add_widths(row);
|
|
|
|
|
}
|
|
|
|
|
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
let row = Row {
|
2017-07-04 07:29:36 +00:00
|
|
|
|
tree: tree_params,
|
2017-07-03 21:22:40 +00:00
|
|
|
|
cells: egg.table_row,
|
2017-07-08 11:24:22 +00:00
|
|
|
|
name: self.style.for_file(&egg.file, self.colours)
|
|
|
|
|
.with_link_paths()
|
|
|
|
|
.paint().promote(),
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
};
|
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
|
rows.push(row);
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
|
|
|
|
|
if let Some(ref dir) = egg.dir {
|
2017-09-28 08:09:57 +00:00
|
|
|
|
for file_to_add in dir.files(self.filter.dot_filter, ignore) {
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
match file_to_add {
|
|
|
|
|
Ok(f) => files.push(f),
|
|
|
|
|
Err((path, e)) => errors.push((e, Some(path)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-26 07:28:32 +00:00
|
|
|
|
self.filter.filter_child_files(&mut files);
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
|
|
|
|
|
if !files.is_empty() {
|
|
|
|
|
for xattr in egg.xattrs {
|
2017-07-03 21:46:40 +00:00
|
|
|
|
rows.push(self.render_xattr(xattr, TreeParams::new(depth.deeper(), false)));
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (error, path) in errors {
|
2017-07-03 21:46:40 +00:00
|
|
|
|
rows.push(self.render_error(&error, TreeParams::new(depth.deeper(), false), path));
|
2015-08-26 10:36:10 +00:00
|
|
|
|
}
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
|
2018-02-14 01:53:53 +00:00
|
|
|
|
self.add_files_to_table(pool, table, rows, &files, ignore, depth.deeper());
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
continue;
|
2015-02-26 07:18:08 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-26 10:36:10 +00:00
|
|
|
|
|
Parallelise the details view!
This commit removes the threadpool in `main.rs` that stats each command-line argument separately, and replaces it with a *scoped* threadpool in `options/details.rs` that builds the table in parallel! Running this on my machine halves the execution time when tree-ing my entire home directory (which isn't exactly a common occurrence, but it's the only way to give exa a large running time)
The statting will be added back in parallel at a later stage. This was facilitated by the previous changes to recursion that made it easier to deal with.
There's a lot of large sweeping architectural changes. Here's a smattering of them:
- In `main.rs`, the files are now passed around as vectors of files rather than array slices of files. This is because `File`s aren't `Clone`, and the `Vec` is necessary to give away ownership of the files at the appropriate point.
- In the details view, files are now sorted *all* the time, rather than obeying the command-line order. As they're run in parallel, they have no guaranteed order anyway, so we *have* to sort them again. (I'm not sure if this should be the intended behaviour or not!) This means that the `Details` struct has to have the filter *all* the time, not only while recursing, so it's been moved out of the `recurse` field.
- We use `scoped_threadpool` over `threadpool`, a recent addition. It's only safely used on Nightly, which we're using anyway, so that's OK!
- Removed a bunch of out-of-date comments.
This also fixes #77, mainly by accident :)
2015-09-02 22:19:10 +00:00
|
|
|
|
let count = egg.xattrs.len();
|
|
|
|
|
for (index, xattr) in egg.xattrs.into_iter().enumerate() {
|
2017-07-03 21:46:40 +00:00
|
|
|
|
rows.push(self.render_xattr(xattr, TreeParams::new(depth.deeper(), errors.is_empty() && index == count - 1)));
|
2015-08-26 10:36:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let count = errors.len();
|
|
|
|
|
for (index, (error, path)) in errors.into_iter().enumerate() {
|
2017-07-03 21:46:40 +00:00
|
|
|
|
rows.push(self.render_error(&error, TreeParams::new(depth.deeper(), index == count - 1), path));
|
2015-08-26 10:36:10 +00:00
|
|
|
|
}
|
2015-02-05 14:39:56 +00:00
|
|
|
|
}
|
2015-02-26 07:18:08 +00:00
|
|
|
|
}
|
2015-02-05 14:39:56 +00:00
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
|
pub fn render_header(&self, header: TableRow) -> Row {
|
|
|
|
|
Row {
|
2017-07-03 22:25:56 +00:00
|
|
|
|
tree: TreeParams::new(TreeDepth::root(), false),
|
2017-07-02 00:02:17 +00:00
|
|
|
|
cells: Some(header),
|
2017-06-24 21:39:15 +00:00
|
|
|
|
name: TextCell::paint_str(self.colours.header, "Name"),
|
2017-07-02 00:02:17 +00:00
|
|
|
|
}
|
2015-02-26 07:18:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-03 21:22:40 +00:00
|
|
|
|
fn render_error(&self, error: &IOError, tree: TreeParams, path: Option<PathBuf>) -> Row {
|
2017-10-02 19:13:30 +00:00
|
|
|
|
use output::file_name::Colours;
|
|
|
|
|
|
2015-08-25 14:04:15 +00:00
|
|
|
|
let error_message = match path {
|
|
|
|
|
Some(path) => format!("<{}: {}>", path.display(), error),
|
|
|
|
|
None => format!("<{}>", error),
|
|
|
|
|
};
|
|
|
|
|
|
2017-10-08 15:59:11 +00:00
|
|
|
|
// TODO: broken_symlink() doesn’t quite seem like the right name for
|
|
|
|
|
// the style that’s being used here. Maybe split it in two?
|
|
|
|
|
let name = TextCell::paint(self.colours.broken_symlink(), error_message);
|
2017-07-03 21:22:40 +00:00
|
|
|
|
Row { cells: None, name, tree }
|
2015-08-25 20:08:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-03 21:22:40 +00:00
|
|
|
|
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 }
|
Replace Cells with growable TextCells
A recent change to ansi-term [1] means that `ANSIString`s can now hold either
owned *or* borrowed data (Rust calls this the Cow type). This means that we
can delay formatting ANSIStrings into ANSI-control-code-formatted strings
until it's absolutely necessary. The process for doing this was:
1. Replace the `Cell` type with a `TextCell` type that holds a vector of
`ANSIString` values instead of a formatted string. It still does the
width tracking.
2. Rework the details module's `render` functions to emit values of this
type.
3. Similarly, rework the functions that produce cells containing filenames
to use a `File` value's `name` field, which is an owned `String` that
can now be re-used.
4. Update the printing, formatting, and width-calculating code in the
details and grid-details views to produce a table by adding vectors
together instead of adding strings together, delaying the formatting as
long as it can.
This results in fewer allocations (as fewer `String` values are produced), and
makes the API tidier (as fewer `String` values are being passed around without
having their contents specified).
This also paves the way to Windows support, or at least support for
non-ANSI terminals: by delaying the time until strings are formatted,
it'll now be easier to change *how* they are formatted.
Casualties include:
- Bump to ansi_term v0.7.1, which impls `PartialEq` and `Debug` on
`ANSIString`.
- The grid_details and lines views now need to take a vector of files, rather
than a borrowed slice, so the filename cells produced now own the filename
strings that get taken from files.
- Fixed the signature of `File#link_target` to specify that the
file produced refers to the same directory, rather than some phantom
directory with the same lifetime as the file. (This was wrong from the
start, but it broke nothing until now)
References:
[1]: ansi-term@f6a6579ba8174de1cae64d181ec04af32ba2a4f0
2015-12-17 00:25:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-03 21:22:40 +00:00
|
|
|
|
pub fn render_file(&self, cells: TableRow, name: TextCell, tree: TreeParams) -> Row {
|
|
|
|
|
Row { cells: Some(cells), name, tree }
|
2017-05-21 09:48:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-03 19:12:32 +00:00
|
|
|
|
pub fn iterate_with_table(&'a self, table: Table<'a>, rows: Vec<Row>) -> TableIter<'a> {
|
|
|
|
|
TableIter {
|
2017-07-02 00:02:17 +00:00
|
|
|
|
tree_trunk: TreeTrunk::default(),
|
2017-07-03 19:21:33 +00:00
|
|
|
|
total_width: table.widths().total(),
|
2017-07-02 00:02:17 +00:00
|
|
|
|
table: table,
|
|
|
|
|
inner: rows.into_iter(),
|
2017-08-20 20:39:52 +00:00
|
|
|
|
tree_style: self.colours.punctuation,
|
2015-05-12 02:36:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-03 19:12:32 +00:00
|
|
|
|
|
2017-08-20 20:39:52 +00:00
|
|
|
|
pub fn iterate(&'a self, rows: Vec<Row>) -> Iter {
|
2017-07-03 19:12:32 +00:00
|
|
|
|
Iter {
|
|
|
|
|
tree_trunk: TreeTrunk::default(),
|
|
|
|
|
inner: rows.into_iter(),
|
2017-08-20 20:39:52 +00:00
|
|
|
|
tree_style: self.colours.punctuation,
|
2017-07-03 19:12:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-02 00:02:17 +00:00
|
|
|
|
}
|
2015-05-12 02:36:47 +00:00
|
|
|
|
|
2017-07-04 07:10:37 +00:00
|
|
|
|
|
|
|
|
|
pub struct Row {
|
|
|
|
|
|
|
|
|
|
/// Vector of cells to display.
|
|
|
|
|
///
|
|
|
|
|
/// Most of the rows will be used to display files' metadata, so this will
|
|
|
|
|
/// almost always be `Some`, containing a vector of cells. It will only be
|
|
|
|
|
/// `None` for a row displaying an attribute or error, neither of which
|
|
|
|
|
/// have cells.
|
|
|
|
|
pub cells: Option<TableRow>,
|
|
|
|
|
|
|
|
|
|
/// This file's name, in coloured output. The name is treated separately
|
|
|
|
|
/// from the other cells, as it never requires padding.
|
|
|
|
|
pub name: TextCell,
|
|
|
|
|
|
|
|
|
|
/// Information used to determine which symbols to display in a tree.
|
|
|
|
|
pub tree: TreeParams,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-07-03 19:12:32 +00:00
|
|
|
|
pub struct TableIter<'a> {
|
2017-08-20 20:39:52 +00:00
|
|
|
|
inner: VecIntoIter<Row>,
|
2017-07-03 19:12:32 +00:00
|
|
|
|
table: Table<'a>,
|
2017-08-20 20:39:52 +00:00
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
|
total_width: usize,
|
2017-08-20 20:39:52 +00:00
|
|
|
|
tree_style: Style,
|
|
|
|
|
tree_trunk: TreeTrunk,
|
2017-07-02 00:02:17 +00:00
|
|
|
|
}
|
2015-06-28 12:21:21 +00:00
|
|
|
|
|
2017-07-03 19:12:32 +00:00
|
|
|
|
impl<'a> Iterator for TableIter<'a> {
|
2017-07-02 00:02:17 +00:00
|
|
|
|
type Item = TextCell;
|
2015-06-28 12:21:21 +00:00
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
|
self.inner.next().map(|row| {
|
|
|
|
|
let mut cell =
|
2017-07-03 19:12:32 +00:00
|
|
|
|
if let Some(cells) = row.cells {
|
|
|
|
|
self.table.render(cells)
|
2015-08-25 10:45:27 +00:00
|
|
|
|
}
|
2017-07-02 00:02:17 +00:00
|
|
|
|
else {
|
|
|
|
|
let mut cell = TextCell::default();
|
|
|
|
|
cell.add_spaces(self.total_width);
|
|
|
|
|
cell
|
|
|
|
|
};
|
2015-02-05 14:39:56 +00:00
|
|
|
|
|
2017-07-03 21:22:40 +00:00
|
|
|
|
for tree_part in self.tree_trunk.new_row(row.tree) {
|
2017-08-20 20:39:52 +00:00
|
|
|
|
cell.push(self.tree_style.paint(tree_part.ascii_art()), 4);
|
2015-08-25 20:08:25 +00:00
|
|
|
|
}
|
2015-02-05 14:39:56 +00:00
|
|
|
|
|
2015-08-25 20:08:25 +00:00
|
|
|
|
// If any tree characters have been printed, then add an extra
|
|
|
|
|
// space, which makes the output look much better.
|
2017-07-03 22:25:56 +00:00
|
|
|
|
if !row.tree.is_at_root() {
|
2017-07-03 19:12:32 +00:00
|
|
|
|
cell.add_spaces(1);
|
2015-02-05 14:39:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-03 19:12:32 +00:00
|
|
|
|
cell.append(row.name);
|
2017-07-02 00:02:17 +00:00
|
|
|
|
cell
|
|
|
|
|
})
|
2015-02-05 14:39:56 +00:00
|
|
|
|
}
|
2015-02-26 07:18:08 +00:00
|
|
|
|
}
|
2017-07-02 00:02:17 +00:00
|
|
|
|
|
2017-07-03 19:12:32 +00:00
|
|
|
|
|
2017-08-20 20:39:52 +00:00
|
|
|
|
pub struct Iter {
|
2017-07-03 19:12:32 +00:00
|
|
|
|
tree_trunk: TreeTrunk,
|
2017-08-20 20:39:52 +00:00
|
|
|
|
tree_style: Style,
|
2017-07-03 19:12:32 +00:00
|
|
|
|
inner: VecIntoIter<Row>,
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-20 20:39:52 +00:00
|
|
|
|
impl Iterator for Iter {
|
2017-07-03 19:12:32 +00:00
|
|
|
|
type Item = TextCell;
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
|
self.inner.next().map(|row| {
|
|
|
|
|
let mut cell = TextCell::default();
|
|
|
|
|
|
2017-07-03 21:22:40 +00:00
|
|
|
|
for tree_part in self.tree_trunk.new_row(row.tree) {
|
2017-08-20 20:39:52 +00:00
|
|
|
|
cell.push(self.tree_style.paint(tree_part.ascii_art()), 4);
|
2017-07-03 19:12:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If any tree characters have been printed, then add an extra
|
|
|
|
|
// space, which makes the output look much better.
|
2017-07-03 22:25:56 +00:00
|
|
|
|
if !row.tree.is_at_root() {
|
2017-07-03 19:12:32 +00:00
|
|
|
|
cell.add_spaces(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cell.append(row.name);
|
|
|
|
|
cell
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|