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-12-22 01:15:59 +00:00
|
|
|
use std::ops::Add;
|
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-07-02 00:02:17 +00:00
|
|
|
use fs::{Dir, File};
|
2016-04-16 17:59:25 +00:00
|
|
|
use fs::feature::xattr::{Attribute, FileAttributes};
|
2015-12-22 01:15:59 +00:00
|
|
|
use options::{FileFilter, RecurseOptions};
|
|
|
|
use output::colours::Colours;
|
2017-07-02 00:02:17 +00:00
|
|
|
use output::column::Columns;
|
|
|
|
use output::cell::TextCell;
|
2015-12-22 04:44:51 +00:00
|
|
|
use output::tree::TreeTrunk;
|
2017-05-07 14:31:00 +00:00
|
|
|
use output::file_name::{FileName, LinkStyle, Classify};
|
2017-07-02 00:02:17 +00:00
|
|
|
use output::table::{Table, Environment, Row as TableRow};
|
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.
|
2016-10-30 14:31:25 +00:00
|
|
|
#[derive(PartialEq, Debug, Clone, Default)]
|
2017-06-25 23:53:48 +00:00
|
|
|
pub struct Options {
|
2015-02-26 08:27:29 +00:00
|
|
|
|
|
|
|
/// A Columns object that says which columns should be included in the
|
|
|
|
/// output in the general case. Directories themselves can pick which
|
|
|
|
/// columns are *added* to this list, such as the Git column.
|
2015-08-03 12:54:25 +00:00
|
|
|
pub columns: Option<Columns>,
|
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,
|
|
|
|
pub classify: Classify,
|
|
|
|
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> {
|
|
|
|
pub fn render<W: Write>(self, w: &mut W) -> IOResult<()> {
|
|
|
|
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
|
|
|
|
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(columns) = self.opts.columns {
|
|
|
|
let env = Environment::default();
|
|
|
|
let colz = columns.for_dir(self.dir);
|
|
|
|
let mut table = Table::new(&colz, &self.colours, &env);
|
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();
|
|
|
|
rows.push(self.render_header(header));
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut table = Some(table);
|
|
|
|
self.add_files_to_table(&mut table, &mut rows, &self.files, 0);
|
2015-02-26 07:18:08 +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
|
|
|
for row in self.iterate(table.as_ref(), rows) {
|
|
|
|
writeln!(w, "{}", row.strings())?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
self.add_files_to_table(&mut None, &mut rows, &self.files, 0);
|
|
|
|
|
|
|
|
for row in self.iterate(None, rows) {
|
|
|
|
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.
|
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
|
|
|
fn add_files_to_table<'dir>(&self, table: &mut Option<Table<'a>>, rows: &mut Vec<Row>, src: &Vec<File<'dir>>, depth: usize) {
|
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 num_cpus;
|
|
|
|
use scoped_threadpool::Pool;
|
|
|
|
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 pool = Pool::new(num_cpus::get() as u32);
|
|
|
|
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
|
|
|
|
|
|
|
if xattr::ENABLED {
|
|
|
|
match file.path.attributes() {
|
|
|
|
Ok(xs) => xattrs.extend(xs),
|
|
|
|
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
|
|
|
|
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 {
|
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 file.is_directory() && r.tree && !r.is_too_deep(depth) {
|
Override the names of . and ..
There was a problem when displaying . and .. in directory listings: their names would normalise to actual names! So instead of literally seeing `.`, you’d see the current directory’s name, inserted in sort order into the list of results. Obviously this is not what we want.
In unrelated news, putting `.` and `..` into the list of paths read from a directory just takes up more heap space for something that’s basically constant.
We can solve both these problems at once by moving the DotFilter to the files iterator in Dir, rather than at the Dir’s creation. Having the iterator know whether it should display `.` and `..` means it can emit those files first, and because it knows what those files really represent, it can override their file names to actually be those sequences of dots.
This is not a perfect solution: the main casualty is that a File can now be constructed with a name, some metadata, both, or neither. This is currently handled with a bunch of Options, and returns IOResult even without doing any IO operations.
But at least all the tests pass!
2017-06-28 17:41:31 +00:00
|
|
|
if let Ok(d) = file.to_dir(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
|
|
|
dir = Some(d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
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
|
|
|
|
|
|
|
let num_eggs = file_eggs.len();
|
|
|
|
for (index, egg) in file_eggs.into_iter().enumerate() {
|
|
|
|
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 {
|
|
|
|
depth: depth,
|
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
|
|
|
cells: egg.table_row,
|
2017-07-02 00:02:17 +00:00
|
|
|
name: FileName::new(&egg.file, LinkStyle::FullLinkPaths, self.classify, self.colours).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
|
|
|
last: index == num_eggs - 1,
|
|
|
|
};
|
|
|
|
|
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 {
|
Override the names of . and ..
There was a problem when displaying . and .. in directory listings: their names would normalise to actual names! So instead of literally seeing `.`, you’d see the current directory’s name, inserted in sort order into the list of results. Obviously this is not what we want.
In unrelated news, putting `.` and `..` into the list of paths read from a directory just takes up more heap space for something that’s basically constant.
We can solve both these problems at once by moving the DotFilter to the files iterator in Dir, rather than at the Dir’s creation. Having the iterator know whether it should display `.` and `..` means it can emit those files first, and because it knows what those files really represent, it can override their file names to actually be those sequences of dots.
This is not a perfect solution: the main casualty is that a File can now be constructed with a name, some metadata, both, or neither. This is currently handled with a bunch of Options, and returns IOResult even without doing any IO operations.
But at least all the tests pass!
2017-06-28 17:41:31 +00:00
|
|
|
for file_to_add in dir.files(self.filter.dot_filter) {
|
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-02 00:02:17 +00:00
|
|
|
rows.push(self.render_xattr(xattr, depth + 1, 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-02 00:02:17 +00:00
|
|
|
rows.push(self.render_error(&error, depth + 1, 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
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
self.add_files_to_table(table, rows, &files, depth + 1);
|
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-02 00:02:17 +00:00
|
|
|
rows.push(self.render_xattr(xattr, depth + 1, 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-02 00:02:17 +00:00
|
|
|
rows.push(self.render_error(&error, depth + 1, 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 {
|
2015-02-26 08:27:29 +00:00
|
|
|
depth: 0,
|
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"),
|
2015-02-26 08:27:29 +00:00
|
|
|
last: false,
|
2017-07-02 00:02:17 +00:00
|
|
|
}
|
2015-02-26 07:18:08 +00:00
|
|
|
}
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
fn render_error(&self, error: &IOError, depth: usize, last: bool, path: Option<PathBuf>) -> Row {
|
2015-08-25 14:04:15 +00:00
|
|
|
let error_message = match path {
|
|
|
|
Some(path) => format!("<{}: {}>", path.display(), error),
|
|
|
|
None => format!("<{}>", error),
|
|
|
|
};
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
Row {
|
2015-08-25 14:04:15 +00:00
|
|
|
depth: depth,
|
|
|
|
cells: None,
|
2017-06-24 21:39:15 +00:00
|
|
|
name: TextCell::paint(self.colours.broken_arrow, error_message),
|
2015-08-25 14:04:15 +00:00
|
|
|
last: last,
|
2017-07-02 00:02:17 +00:00
|
|
|
}
|
2015-08-25 20:08:25 +00:00
|
|
|
}
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
fn render_xattr(&self, xattr: Attribute, depth: usize, last: bool) -> Row {
|
|
|
|
Row {
|
2015-08-25 20:08:25 +00:00
|
|
|
depth: depth,
|
|
|
|
cells: None,
|
2017-06-24 21:39:15 +00:00
|
|
|
name: TextCell::paint(self.colours.perms.attribute, format!("{} (len {})", xattr.name, xattr.size)),
|
2015-08-25 20:08:25 +00:00
|
|
|
last: last,
|
2017-07-02 00:02:17 +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
|
|
|
}
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
pub fn render_file(&self, cells: TableRow, name_cell: TextCell, depth: usize, last: bool) -> Row {
|
|
|
|
Row {
|
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
|
|
|
depth: depth,
|
|
|
|
cells: Some(cells),
|
|
|
|
name: name_cell,
|
|
|
|
last: last,
|
2017-05-21 09:48:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
/// Render the table as a vector of Cells, to be displayed on standard output.
|
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
|
|
|
pub fn iterate(&self, table: Option<&'a Table<'a>>, rows: Vec<Row>) -> Iter<'a> {
|
2017-07-02 00:02:17 +00:00
|
|
|
Iter {
|
|
|
|
tree_trunk: TreeTrunk::default(),
|
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
|
|
|
total_width: table.map(|t| t.columns_count() + t.widths().iter().fold(0, Add::add)).unwrap_or(0),
|
2017-07-02 00:02:17 +00:00
|
|
|
table: table,
|
|
|
|
inner: rows.into_iter(),
|
|
|
|
colours: self.colours,
|
2015-05-12 02:36:47 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-02 00:02:17 +00:00
|
|
|
}
|
2015-05-12 02:36:47 +00:00
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
pub struct Iter<'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: Option<&'a Table<'a>>,
|
2017-07-02 00:02:17 +00:00
|
|
|
tree_trunk: TreeTrunk,
|
|
|
|
total_width: usize,
|
|
|
|
colours: &'a Colours,
|
|
|
|
inner: VecIntoIter<Row>,
|
|
|
|
}
|
2015-06-28 12:21:21 +00:00
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
impl<'a> Iterator for Iter<'a> {
|
|
|
|
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 =
|
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(table), Some(cells)) = (self.table, row.cells) {
|
|
|
|
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
|
|
|
|
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
|
|
|
let mut filename = TextCell::default();
|
2015-06-28 12:21:21 +00:00
|
|
|
|
2017-07-02 00:02:17 +00:00
|
|
|
for tree_part in self.tree_trunk.new_row(row.depth, row.last) {
|
2017-06-24 21:39:15 +00:00
|
|
|
filename.push(self.colours.punctuation.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.
|
|
|
|
if row.depth != 0 {
|
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
|
|
|
filename.add_spaces(1);
|
2015-02-05 14:39:56 +00:00
|
|
|
}
|
|
|
|
|
2015-02-26 08:27:29 +00:00
|
|
|
// Print the name without worrying about padding.
|
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
|
|
|
filename.append(row.name);
|
2015-02-24 16:05:25 +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
|
|
|
cell.append(filename);
|
2015-06-28 12:21:21 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
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,
|
|
|
|
|
|
|
|
/// How many directories deep into the tree structure this is. Directories
|
|
|
|
/// on top have depth 0.
|
|
|
|
pub depth: usize,
|
|
|
|
|
|
|
|
/// Whether this is the last entry in the directory. This flag is used
|
|
|
|
/// when calculating the tree view.
|
|
|
|
pub last: bool,
|
|
|
|
}
|