exa/src/output/details.rs

578 lines
21 KiB
Rust
Raw Normal View History

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:
//!
//! ```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
//! ```
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:
//!
//! ```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 │
//! └─────────────────────────────────────────────────────────────────────────┘
//! ```
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.
//!
//!
//! ## Extended Attributes and Errors
//!
//! Finally, files' extended attributes and any errors that occur while statting
//! them can also be displayed as their children. It looks like this:
//!
//! ```text
2015-09-03 17:48:53 +00:00
//! .rw-r--r-- 0 ben 3 Sep 13:26 forbidden
//! └── <Permission denied (os error 13)>
//! .rw-r--r--@ 0 ben 3 Sep 13:26 file_with_xattrs
//! ├── another_greeting (len 2)
//! └── greeting (len 5)
//! ```
2015-09-03 17:48:53 +00:00
//!
//! These lines also have `None` cells, and the error string or attribute details
//! are used in place of the filename.
use std::io::{Write, Error as IOError, Result as IOResult};
use std::ops::Add;
use std::path::PathBuf;
use std::sync::{Arc, Mutex, MutexGuard};
use datetime::fmt::DateFormat;
use datetime::{LocalDateTime, DatePiece};
use datetime::TimeZone;
2016-02-10 19:11:10 +00:00
use zoneinfo_compiled::{CompiledData, Result as TZResult};
2015-06-08 20:33:39 +00:00
use locale;
use users::{Users, Groups, UsersCache};
2015-06-08 20:33:39 +00:00
use fs::{Dir, File, fields as f};
use fs::feature::xattr::{Attribute, FileAttributes};
use options::{FileFilter, RecurseOptions};
use output::colours::Colours;
2017-05-20 20:43:04 +00:00
use output::column::{Alignment, Column, Columns};
use output::cell::{TextCell, TextCellContents};
use output::tree::TreeTrunk;
2017-05-07 14:31:00 +00:00
use output::file_name::{FileName, LinkStyle, Classify};
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.
#[derive(PartialEq, Debug, Clone, Default)]
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.
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,
}
/// The **environment** struct contains any data that could change between
/// running instances of exa, depending on the user's computer's configuration.
///
/// Any environment field should be able to be mocked up for test runs.
pub struct Environment<U> { // where U: Users+Groups
/// The year of the current time. This gets used to determine which date
/// format to use.
current_year: i64,
/// Localisation rules for formatting numbers.
numeric: locale::Numeric,
/// Localisation rules for formatting timestamps.
time: locale::Time,
/// Date format for printing out timestamps that are in the current year.
date_and_time: DateFormat<'static>,
/// Date format for printing out timestamps that *arent*.
date_and_year: DateFormat<'static>,
/// The computer's current time zone. This gets used to determine how to
/// offset files' timestamps.
tz: Option<TimeZone>,
/// Mapping cache of user IDs to usernames.
users: Mutex<U>,
}
impl<U> Environment<U> {
pub fn lock_users(&self) -> MutexGuard<U> {
self.users.lock().unwrap()
}
}
impl Default for Environment<UsersCache> {
fn default() -> Self {
use unicode_width::UnicodeWidthStr;
let tz = determine_time_zone();
if let Err(ref e) = tz {
println!("Unable to determine time zone: {}", e);
}
let numeric = locale::Numeric::load_user_locale()
.unwrap_or_else(|_| locale::Numeric::english());
let time = locale::Time::load_user_locale()
.unwrap_or_else(|_| locale::Time::english());
// Some locales use a three-character wide month name (Jan to Dec);
// others vary between three and four (1月 to 12月). We assume that
// December is the month with the maximum width, and use the width of
// that to determine how to pad the other months.
let december_width = UnicodeWidthStr::width(&*time.short_month_name(11));
let date_and_time = match december_width {
4 => DateFormat::parse("{2>:D} {4>:M} {2>:h}:{02>:m}").unwrap(),
_ => DateFormat::parse("{2>:D} {:M} {2>:h}:{02>:m}").unwrap(),
};
let date_and_year = match december_width {
4 => DateFormat::parse("{2>:D} {4>:M} {5>:Y}").unwrap(),
_ => DateFormat::parse("{2>:D} {:M} {5>:Y}").unwrap()
};
Environment {
current_year: LocalDateTime::now().year(),
numeric: numeric,
date_and_time: date_and_time,
date_and_year: date_and_year,
time: time,
tz: tz.ok(),
users: Mutex::new(UsersCache::new()),
}
}
}
2016-02-10 19:11:10 +00:00
fn determine_time_zone() -> TZResult<TimeZone> {
TimeZone::from_file("/etc/localtime")
2016-02-10 19:02:20 +00:00
}
2015-09-03 17:48:53 +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,
/// 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,
}
impl<'a> Render<'a> {
pub fn render<W: Write>(&self, w: &mut W) -> IOResult<()> {
2015-09-03 17:48:53 +00:00
2015-02-26 08:27:29 +00:00
// First, transform the Columns object into a vector of columns for
// the current directory.
let columns_for_dir = match self.opts.columns {
Some(cols) => cols.for_dir(self.dir),
None => Vec::new(),
};
// Then, retrieve various environment variables.
let env = Arc::new(Environment::<UsersCache>::default());
// Build the table to put rows in.
let mut table = Table {
columns: &*columns_for_dir,
colours: self.colours,
classify: self.classify,
xattr: self.opts.xattr,
env: env,
rows: Vec::new(),
};
2015-09-03 17:48:53 +00:00
// Next, add a header if the user requests it.
if self.opts.header { table.add_header() }
2015-02-26 08:27:29 +00:00
// Then add files to the table and print it out.
self.add_files_to_table(&mut table, &self.files, 0);
for cell in table.print_table() {
2017-03-26 16:35:50 +00:00
writeln!(w, "{}", cell.strings())?;
}
Ok(())
}
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.
fn add_files_to_table<'dir, U: Users+Groups+Send>(&self, mut table: &mut Table<U>, 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};
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();
struct Egg<'a> {
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
cells: Vec<TextCell>,
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
xattrs: Vec<Attribute>,
errors: Vec<(IOError, Option<PathBuf>)>,
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: Option<Dir>,
file: &'a File<'a>,
}
impl<'a> AsRef<File<'a>> for Egg<'a> {
fn as_ref(&self) -> &File<'a> {
self.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
}
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
pool.scoped(|scoped| {
let file_eggs = Arc::new(Mutex::new(&mut file_eggs));
let table = Arc::new(&mut table);
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();
let table = table.clone();
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();
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
let cells = table.cells_for_file(&file, !xattrs.is_empty());
2015-09-03 17:48:53 +00:00
if !table.xattr {
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;
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) {
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);
}
}
};
let egg = Egg { cells, 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);
});
}
});
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;
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,
cells: Some(egg.cells),
name: FileName::new(&egg.file, LinkStyle::FullLinkPaths, table.classify, table.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,
};
table.rows.push(row);
if let Some(ref dir) = egg.dir {
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)))
}
}
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 {
table.add_xattr(xattr, depth + 1, false);
}
for (error, path) in errors {
table.add_error(&error, depth + 1, false, path);
}
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
self.add_files_to_table(table, &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;
}
}
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() {
table.add_xattr(xattr, depth + 1, errors.is_empty() && index == count - 1);
}
let count = errors.len();
for (index, (error, path)) in errors.into_iter().enumerate() {
table.add_error(&error, depth + 1, index == count - 1, path);
}
}
}
}
2015-06-08 20:33:39 +00:00
pub struct Row {
2015-02-26 08:27:29 +00:00
/// Vector of cells to display.
2015-08-25 10:50:07 +00:00
///
2015-09-03 17:48:53 +00:00
/// 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.
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
cells: Option<Vec<TextCell>>,
2015-02-26 08:27:29 +00:00
/// This file's name, in coloured output. The name is treated separately
/// from the other cells, as it never requires 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
name: TextCell,
2015-02-26 08:27:29 +00:00
/// How many directories deep into the tree structure this is. Directories
/// on top have depth 0.
2015-08-25 10:50:07 +00:00
depth: usize,
2015-02-26 08:27:29 +00:00
/// Whether this is the last entry in the directory. This flag is used
/// when calculating the tree view.
2015-08-25 10:50:07 +00:00
last: bool,
}
impl Row {
2015-08-25 10:50:07 +00:00
2015-09-03 17:48:53 +00:00
/// Gets the Unicode display width of the indexed column, if present. If
/// not, returns 0.
fn column_width(&self, index: usize) -> usize {
match self.cells {
Some(ref cells) => *cells[index].width,
None => 0,
}
}
}
2015-06-08 20:33:39 +00:00
2015-02-26 08:27:29 +00:00
/// A **Table** object gets built up by the view as it lists files and
/// directories.
pub struct Table<'a, U: 'a> { // where U: Users+Groups
pub rows: Vec<Row>,
pub columns: &'a [Column],
pub colours: &'a Colours,
pub xattr: bool,
pub classify: Classify,
pub env: Arc<Environment<U>>,
}
impl<'a, U: Users+Groups+'a> Table<'a, U> {
2015-02-26 08:27:29 +00:00
/// Add a dummy "header" row to the table, which contains the names of all
/// the columns, underlined. This has dummy data for the cases that aren't
/// actually used, such as the depth or list of attributes.
pub fn add_header(&mut self) {
let row = Row {
2015-02-26 08:27:29 +00:00
depth: 0,
cells: Some(self.columns.iter().map(|c| TextCell::paint_str(self.colours.header, c.header())).collect()),
name: TextCell::paint_str(self.colours.header, "Name"),
2015-02-26 08:27:29 +00:00
last: false,
};
self.rows.push(row);
}
fn add_error(&mut self, error: &IOError, depth: usize, last: bool, path: Option<PathBuf>) {
let error_message = match path {
Some(path) => format!("<{}: {}>", path.display(), error),
None => format!("<{}>", error),
};
let row = Row {
depth: depth,
cells: None,
name: TextCell::paint(self.colours.broken_arrow, error_message),
last: last,
};
self.rows.push(row);
}
fn add_xattr(&mut self, xattr: Attribute, depth: usize, last: bool) {
let row = Row {
depth: depth,
cells: None,
name: TextCell::paint(self.colours.perms.attribute, format!("{} (len {})", xattr.name, xattr.size)),
last: last,
};
self.rows.push(row);
}
pub fn filename(&self, file: &File, links: LinkStyle) -> TextCellContents {
FileName::new(file, links, self.classify, &self.colours).paint()
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
}
pub fn add_file_with_cells(&mut self, cells: Vec<TextCell>, name_cell: TextCell, depth: usize, last: bool) {
let 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,
};
2015-05-12 02:14:56 +00:00
self.rows.push(row);
}
2015-02-26 08:27:29 +00:00
/// Use the list of columns to find which cells should be produced for
/// this file, per-column.
pub fn cells_for_file(&self, file: &File, xattrs: bool) -> Vec<TextCell> {
2017-03-31 16:08:11 +00:00
self.columns.iter()
.map(|c| self.display(file, c, xattrs))
.collect()
}
fn permissions_plus(&self, file: &File, xattrs: bool) -> f::PermissionsPlus {
f::PermissionsPlus {
file_type: file.type_char(),
permissions: file.permissions(),
xattrs: xattrs,
}
}
fn display(&self, file: &File, column: &Column, xattrs: bool) -> TextCell {
use output::column::TimeType::*;
match *column {
Column::Permissions => self.permissions_plus(file, xattrs).render(&self.colours),
Column::FileSize(fmt) => file.size().render(&self.colours, fmt, &self.env.numeric),
Column::Timestamp(Modified) => file.modified_time().render(&self.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
Column::Timestamp(Created) => file.created_time().render( &self.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
Column::Timestamp(Accessed) => file.accessed_time().render(&self.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
Column::HardLinks => file.links().render(&self.colours, &self.env.numeric),
Column::Inode => file.inode().render(&self.colours),
Column::Blocks => file.blocks().render(&self.colours),
Column::User => file.user().render(&self.colours, &*self.env.lock_users()),
Column::Group => file.group().render(&self.colours, &*self.env.lock_users()),
Column::GitStatus => file.git_status().render(&self.colours),
2015-05-12 02:36:47 +00:00
}
}
2015-08-25 10:50:07 +00:00
/// Render the table as a vector of Cells, to be displayed on standard output.
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
pub fn print_table(self) -> Vec<TextCell> {
let mut tree_trunk = TreeTrunk::default();
let mut cells = Vec::new();
2015-02-26 08:27:29 +00:00
// Work out the list of column widths by finding the longest cell for
// each column, then formatting each cell in that column to be the
// width of that one.
let column_widths: Vec<usize> = (0 .. self.columns.len())
.map(|n| self.rows.iter().map(|row| row.column_width(n)).max().unwrap_or(0))
.collect();
let total_width: usize = self.columns.len() + column_widths.iter().fold(0, Add::add);
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 row in self.rows {
let mut cell = TextCell::default();
if let Some(cells) = row.cells {
for (n, (this_cell, width)) in cells.into_iter().zip(column_widths.iter()).enumerate() {
let padding = width - *this_cell.width;
match self.columns[n].alignment() {
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
Alignment::Left => { cell.append(this_cell); cell.add_spaces(padding); }
Alignment::Right => { cell.add_spaces(padding); cell.append(this_cell); }
}
cell.add_spaces(1);
}
}
else {
cell.add_spaces(total_width)
}
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();
for tree_part in tree_trunk.new_row(row.depth, row.last) {
filename.push(self.colours.punctuation.paint(tree_part.ascii_art()), 4);
}
// If any tree characters have been printed, then add an extra
// space, which makes the output look much better.
if row.depth != 0 {
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-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);
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);
cells.push(cell);
}
cells
}
}