mirror of
https://github.com/Llewellynvdm/exa.git
synced 2025-02-13 07:48:57 +00:00
Rename Columns to table::Options
The views have been renamed to be the Optionses of their module; now the options for the Table — Columns — has followed suit. This works out, because the table module depended on everything in the columns module. It opens the door for other only-table-specific things to be included. The casualty was that by making it non-Clone and non-PartialEq, a bunch of other #[derive]-d types had to have their derivions removed too.
This commit is contained in:
parent
d27812f819
commit
268b7d52dc
@ -23,7 +23,7 @@ pub use self::view::{View, Mode};
|
||||
|
||||
/// These **options** represent a parsed, error-checked versions of the
|
||||
/// user’s command-line options.
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Options {
|
||||
|
||||
/// The action to perform when encountering a directory rather than a
|
||||
@ -124,8 +124,8 @@ impl Options {
|
||||
/// results will end up being displayed.
|
||||
pub fn should_scan_for_git(&self) -> bool {
|
||||
match self.view.mode {
|
||||
Mode::Details(details::Options { columns: Some(cols), .. }) |
|
||||
Mode::GridDetails(_, details::Options { columns: Some(cols), .. }) => cols.should_scan_for_git(),
|
||||
Mode::Details(details::Options { columns: Some(ref cols), .. }) |
|
||||
Mode::GridDetails(_, details::Options { columns: Some(ref cols), .. }) => cols.should_scan_for_git(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -201,13 +201,13 @@ mod test {
|
||||
#[test]
|
||||
fn long_across() {
|
||||
let opts = Options::getopts(&[ "--long", "--across" ]);
|
||||
assert_eq!(opts, Err(Misfire::Useless("across", true, "long")))
|
||||
assert_eq!(opts.unwrap_err(), Misfire::Useless("across", true, "long"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oneline_across() {
|
||||
let opts = Options::getopts(&[ "--oneline", "--across" ]);
|
||||
assert_eq!(opts, Err(Misfire::Useless("across", true, "oneline")))
|
||||
assert_eq!(opts.unwrap_err(), Misfire::Useless("across", true, "oneline"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -4,14 +4,14 @@ use getopts;
|
||||
|
||||
use output::Colours;
|
||||
use output::{grid, details};
|
||||
use output::column::{Columns, TimeTypes, SizeFormat};
|
||||
use output::table::{TimeTypes, SizeFormat, Options as TableOptions};
|
||||
use output::file_name::Classify;
|
||||
use options::Misfire;
|
||||
use fs::feature::xattr;
|
||||
|
||||
|
||||
/// The **view** contains all information about how to format output.
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct View {
|
||||
pub mode: Mode,
|
||||
pub colours: Colours,
|
||||
@ -31,7 +31,7 @@ impl View {
|
||||
|
||||
|
||||
/// The **mode** is the “type” of output.
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum Mode {
|
||||
Grid(grid::Options),
|
||||
Details(details::Options),
|
||||
@ -54,7 +54,7 @@ impl Mode {
|
||||
}
|
||||
else {
|
||||
Ok(details::Options {
|
||||
columns: Some(Columns::deduce(matches)?),
|
||||
columns: Some(TableOptions::deduce(matches)?),
|
||||
header: matches.opt_present("header"),
|
||||
xattr: xattr::ENABLED && matches.opt_present("extended"),
|
||||
})
|
||||
@ -194,9 +194,9 @@ impl TerminalWidth {
|
||||
}
|
||||
|
||||
|
||||
impl Columns {
|
||||
fn deduce(matches: &getopts::Matches) -> Result<Columns, Misfire> {
|
||||
Ok(Columns {
|
||||
impl TableOptions {
|
||||
fn deduce(matches: &getopts::Matches) -> Result<Self, Misfire> {
|
||||
Ok(TableOptions {
|
||||
size_format: SizeFormat::deduce(matches)?,
|
||||
time_types: TimeTypes::deduce(matches)?,
|
||||
inode: matches.opt_present("inode"),
|
||||
|
@ -1,193 +0,0 @@
|
||||
use fs::Dir;
|
||||
|
||||
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub enum Column {
|
||||
Permissions,
|
||||
FileSize(SizeFormat),
|
||||
Timestamp(TimeType),
|
||||
Blocks,
|
||||
User,
|
||||
Group,
|
||||
HardLinks,
|
||||
Inode,
|
||||
|
||||
GitStatus,
|
||||
}
|
||||
|
||||
/// Each column can pick its own **Alignment**. Usually, numbers are
|
||||
/// right-aligned, and text is left-aligned.
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Alignment {
|
||||
Left, Right,
|
||||
}
|
||||
|
||||
impl Column {
|
||||
|
||||
/// Get the alignment this column should use.
|
||||
pub fn alignment(&self) -> Alignment {
|
||||
match *self {
|
||||
Column::FileSize(_)
|
||||
| Column::HardLinks
|
||||
| Column::Inode
|
||||
| Column::Blocks
|
||||
| Column::GitStatus => Alignment::Right,
|
||||
_ => Alignment::Left,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the text that should be printed at the top, when the user elects
|
||||
/// to have a header row printed.
|
||||
pub fn header(&self) -> &'static str {
|
||||
match *self {
|
||||
Column::Permissions => "Permissions",
|
||||
Column::FileSize(_) => "Size",
|
||||
Column::Timestamp(t) => t.header(),
|
||||
Column::Blocks => "Blocks",
|
||||
Column::User => "User",
|
||||
Column::Group => "Group",
|
||||
Column::HardLinks => "Links",
|
||||
Column::Inode => "inode",
|
||||
Column::GitStatus => "Git",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Debug, Default)]
|
||||
pub struct Columns {
|
||||
pub size_format: SizeFormat,
|
||||
pub time_types: TimeTypes,
|
||||
pub inode: bool,
|
||||
pub links: bool,
|
||||
pub blocks: bool,
|
||||
pub group: bool,
|
||||
pub git: bool
|
||||
}
|
||||
|
||||
impl Columns {
|
||||
pub fn should_scan_for_git(&self) -> bool {
|
||||
self.git
|
||||
}
|
||||
|
||||
pub fn for_dir(&self, dir: Option<&Dir>) -> Vec<Column> {
|
||||
let mut columns = vec![];
|
||||
|
||||
if self.inode {
|
||||
columns.push(Column::Inode);
|
||||
}
|
||||
|
||||
columns.push(Column::Permissions);
|
||||
|
||||
if self.links {
|
||||
columns.push(Column::HardLinks);
|
||||
}
|
||||
|
||||
columns.push(Column::FileSize(self.size_format));
|
||||
|
||||
if self.blocks {
|
||||
columns.push(Column::Blocks);
|
||||
}
|
||||
|
||||
columns.push(Column::User);
|
||||
|
||||
if self.group {
|
||||
columns.push(Column::Group);
|
||||
}
|
||||
|
||||
if self.time_types.modified {
|
||||
columns.push(Column::Timestamp(TimeType::Modified));
|
||||
}
|
||||
|
||||
if self.time_types.created {
|
||||
columns.push(Column::Timestamp(TimeType::Created));
|
||||
}
|
||||
|
||||
if self.time_types.accessed {
|
||||
columns.push(Column::Timestamp(TimeType::Accessed));
|
||||
}
|
||||
|
||||
if cfg!(feature="git") {
|
||||
if let Some(d) = dir {
|
||||
if self.should_scan_for_git() && d.has_git_repo() {
|
||||
columns.push(Column::GitStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
columns
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Formatting options for file sizes.
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub enum SizeFormat {
|
||||
|
||||
/// Format the file size using **decimal** prefixes, such as “kilo”,
|
||||
/// “mega”, or “giga”.
|
||||
DecimalBytes,
|
||||
|
||||
/// Format the file size using **binary** prefixes, such as “kibi”,
|
||||
/// “mebi”, or “gibi”.
|
||||
BinaryBytes,
|
||||
|
||||
/// Do no formatting and just display the size as a number of bytes.
|
||||
JustBytes,
|
||||
}
|
||||
|
||||
impl Default for SizeFormat {
|
||||
fn default() -> SizeFormat {
|
||||
SizeFormat::DecimalBytes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The types of a file’s time fields. These three fields are standard
|
||||
/// across most (all?) operating systems.
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub enum TimeType {
|
||||
|
||||
/// The file’s accessed time (`st_atime`).
|
||||
Accessed,
|
||||
|
||||
/// The file’s modified time (`st_mtime`).
|
||||
Modified,
|
||||
|
||||
/// The file’s creation time (`st_ctime`).
|
||||
Created,
|
||||
}
|
||||
|
||||
impl TimeType {
|
||||
|
||||
/// Returns the text to use for a column’s heading in the columns output.
|
||||
pub fn header(&self) -> &'static str {
|
||||
match *self {
|
||||
TimeType::Accessed => "Date Accessed",
|
||||
TimeType::Modified => "Date Modified",
|
||||
TimeType::Created => "Date Created",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Fields for which of a file’s time fields should be displayed in the
|
||||
/// columns output.
|
||||
///
|
||||
/// There should always be at least one of these--there's no way to disable
|
||||
/// the time columns entirely (yet).
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub struct TimeTypes {
|
||||
pub accessed: bool,
|
||||
pub modified: bool,
|
||||
pub created: bool,
|
||||
}
|
||||
|
||||
impl Default for TimeTypes {
|
||||
|
||||
/// By default, display just the ‘modified’ time. This is the most
|
||||
/// common option, which is why it has this shorthand.
|
||||
fn default() -> TimeTypes {
|
||||
TimeTypes { accessed: false, modified: true, created: false }
|
||||
}
|
||||
}
|
@ -68,11 +68,10 @@ use fs::{Dir, File};
|
||||
use fs::feature::xattr::{Attribute, FileAttributes};
|
||||
use options::{FileFilter, RecurseOptions};
|
||||
use output::colours::Colours;
|
||||
use output::column::Columns;
|
||||
use output::cell::TextCell;
|
||||
use output::tree::{TreeTrunk, TreeParams, TreeDepth};
|
||||
use output::file_name::{FileName, LinkStyle, Classify};
|
||||
use output::table::{Table, Environment, Row as TableRow};
|
||||
use output::table::{Table, Environment, Options as TableOptions, Row as TableRow};
|
||||
|
||||
|
||||
/// With the **Details** view, the output gets formatted into columns, with
|
||||
@ -86,13 +85,14 @@ use output::table::{Table, Environment, Row as TableRow};
|
||||
///
|
||||
/// Almost all the heavy lifting is done in a Table object, which handles the
|
||||
/// columns for each row.
|
||||
#[derive(PartialEq, Debug, Clone, Default)]
|
||||
#[derive(Debug)]
|
||||
pub struct Options {
|
||||
|
||||
/// 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>,
|
||||
/// Options specific to drawing a table.
|
||||
///
|
||||
/// Directories themselves can pick which columns are *added* to this
|
||||
/// list, such as the Git column.
|
||||
pub columns: Option<TableOptions>,
|
||||
|
||||
/// Whether to show a header line or not.
|
||||
pub header: bool,
|
||||
@ -139,7 +139,7 @@ impl<'a> Render<'a> {
|
||||
pub fn render<W: Write>(self, w: &mut W) -> IOResult<()> {
|
||||
let mut rows = Vec::new();
|
||||
|
||||
if let Some(columns) = self.opts.columns {
|
||||
if let Some(ref columns) = self.opts.columns {
|
||||
let env = Environment::load_all();
|
||||
let colz = columns.for_dir(self.dir);
|
||||
let mut table = Table::new(&colz, &self.colours, &env);
|
||||
|
@ -8,12 +8,11 @@ use fs::feature::xattr::FileAttributes;
|
||||
|
||||
use options::FileFilter;
|
||||
use output::cell::TextCell;
|
||||
use output::column::Column;
|
||||
use output::colours::Colours;
|
||||
use output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
|
||||
use output::grid::Options as GridOptions;
|
||||
use output::file_name::{FileName, LinkStyle, Classify};
|
||||
use output::table::{Table, Environment, Row as TableRow};
|
||||
use output::table::{Table, Column, Environment, Row as TableRow};
|
||||
use output::tree::{TreeParams, TreeDepth};
|
||||
|
||||
|
||||
@ -43,7 +42,7 @@ impl<'a> Render<'a> {
|
||||
pub fn render<W: Write>(&self, w: &mut W) -> IOResult<()> {
|
||||
|
||||
let columns_for_dir = match self.details.columns {
|
||||
Some(cols) => cols.for_dir(self.dir),
|
||||
Some(ref cols) => cols.for_dir(self.dir),
|
||||
None => Vec::new(),
|
||||
};
|
||||
|
||||
|
@ -2,12 +2,12 @@ pub use self::cell::{TextCell, TextCellContents, DisplayWidth};
|
||||
pub use self::colours::Colours;
|
||||
pub use self::escape::escape;
|
||||
|
||||
pub mod column;
|
||||
pub mod details;
|
||||
pub mod file_name;
|
||||
pub mod grid_details;
|
||||
pub mod grid;
|
||||
pub mod lines;
|
||||
pub mod table;
|
||||
pub mod time;
|
||||
|
||||
mod cell;
|
||||
@ -15,4 +15,3 @@ mod colours;
|
||||
mod escape;
|
||||
mod render;
|
||||
mod tree;
|
||||
mod table;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use fs::fields as f;
|
||||
use output::column::SizeFormat;
|
||||
use output::cell::{TextCell, DisplayWidth};
|
||||
use output::colours::Colours;
|
||||
use output::table::SizeFormat;
|
||||
use locale;
|
||||
|
||||
|
||||
@ -68,8 +68,8 @@ impl f::DeviceIDs {
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use output::colours::Colours;
|
||||
use output::column::SizeFormat;
|
||||
use output::cell::{TextCell, DisplayWidth};
|
||||
use output::table::SizeFormat;
|
||||
use fs::fields as f;
|
||||
|
||||
use locale;
|
||||
|
@ -11,10 +11,205 @@ use users::UsersCache;
|
||||
|
||||
use output::cell::TextCell;
|
||||
use output::colours::Colours;
|
||||
use output::column::{Alignment, Column};
|
||||
use output::time::TimeFormat;
|
||||
|
||||
use fs::{File, fields as f};
|
||||
use fs::{File, Dir, fields as f};
|
||||
|
||||
|
||||
|
||||
/// Options for displaying a table.
|
||||
#[derive(Debug)]
|
||||
pub struct Options {
|
||||
pub size_format: SizeFormat,
|
||||
pub time_types: TimeTypes,
|
||||
pub inode: bool,
|
||||
pub links: bool,
|
||||
pub blocks: bool,
|
||||
pub group: bool,
|
||||
pub git: bool
|
||||
}
|
||||
|
||||
impl Options {
|
||||
pub fn should_scan_for_git(&self) -> bool {
|
||||
self.git
|
||||
}
|
||||
|
||||
pub fn for_dir(&self, dir: Option<&Dir>) -> Vec<Column> {
|
||||
let mut columns = vec![];
|
||||
|
||||
if self.inode {
|
||||
columns.push(Column::Inode);
|
||||
}
|
||||
|
||||
columns.push(Column::Permissions);
|
||||
|
||||
if self.links {
|
||||
columns.push(Column::HardLinks);
|
||||
}
|
||||
|
||||
columns.push(Column::FileSize(self.size_format));
|
||||
|
||||
if self.blocks {
|
||||
columns.push(Column::Blocks);
|
||||
}
|
||||
|
||||
columns.push(Column::User);
|
||||
|
||||
if self.group {
|
||||
columns.push(Column::Group);
|
||||
}
|
||||
|
||||
if self.time_types.modified {
|
||||
columns.push(Column::Timestamp(TimeType::Modified));
|
||||
}
|
||||
|
||||
if self.time_types.created {
|
||||
columns.push(Column::Timestamp(TimeType::Created));
|
||||
}
|
||||
|
||||
if self.time_types.accessed {
|
||||
columns.push(Column::Timestamp(TimeType::Accessed));
|
||||
}
|
||||
|
||||
if cfg!(feature="git") {
|
||||
if let Some(d) = dir {
|
||||
if self.should_scan_for_git() && d.has_git_repo() {
|
||||
columns.push(Column::GitStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
columns
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A table contains these.
|
||||
#[derive(Debug)]
|
||||
pub enum Column {
|
||||
Permissions,
|
||||
FileSize(SizeFormat),
|
||||
Timestamp(TimeType),
|
||||
Blocks,
|
||||
User,
|
||||
Group,
|
||||
HardLinks,
|
||||
Inode,
|
||||
GitStatus,
|
||||
}
|
||||
|
||||
/// Each column can pick its own **Alignment**. Usually, numbers are
|
||||
/// right-aligned, and text is left-aligned.
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Alignment {
|
||||
Left, Right,
|
||||
}
|
||||
|
||||
impl Column {
|
||||
|
||||
/// Get the alignment this column should use.
|
||||
pub fn alignment(&self) -> Alignment {
|
||||
match *self {
|
||||
Column::FileSize(_)
|
||||
| Column::HardLinks
|
||||
| Column::Inode
|
||||
| Column::Blocks
|
||||
| Column::GitStatus => Alignment::Right,
|
||||
_ => Alignment::Left,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the text that should be printed at the top, when the user elects
|
||||
/// to have a header row printed.
|
||||
pub fn header(&self) -> &'static str {
|
||||
match *self {
|
||||
Column::Permissions => "Permissions",
|
||||
Column::FileSize(_) => "Size",
|
||||
Column::Timestamp(t) => t.header(),
|
||||
Column::Blocks => "Blocks",
|
||||
Column::User => "User",
|
||||
Column::Group => "Group",
|
||||
Column::HardLinks => "Links",
|
||||
Column::Inode => "inode",
|
||||
Column::GitStatus => "Git",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Formatting options for file sizes.
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub enum SizeFormat {
|
||||
|
||||
/// Format the file size using **decimal** prefixes, such as “kilo”,
|
||||
/// “mega”, or “giga”.
|
||||
DecimalBytes,
|
||||
|
||||
/// Format the file size using **binary** prefixes, such as “kibi”,
|
||||
/// “mebi”, or “gibi”.
|
||||
BinaryBytes,
|
||||
|
||||
/// Do no formatting and just display the size as a number of bytes.
|
||||
JustBytes,
|
||||
}
|
||||
|
||||
impl Default for SizeFormat {
|
||||
fn default() -> SizeFormat {
|
||||
SizeFormat::DecimalBytes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The types of a file’s time fields. These three fields are standard
|
||||
/// across most (all?) operating systems.
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub enum TimeType {
|
||||
|
||||
/// The file’s accessed time (`st_atime`).
|
||||
Accessed,
|
||||
|
||||
/// The file’s modified time (`st_mtime`).
|
||||
Modified,
|
||||
|
||||
/// The file’s creation time (`st_ctime`).
|
||||
Created,
|
||||
}
|
||||
|
||||
impl TimeType {
|
||||
|
||||
/// Returns the text to use for a column’s heading in the columns output.
|
||||
pub fn header(&self) -> &'static str {
|
||||
match *self {
|
||||
TimeType::Accessed => "Date Accessed",
|
||||
TimeType::Modified => "Date Modified",
|
||||
TimeType::Created => "Date Created",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Fields for which of a file’s time fields should be displayed in the
|
||||
/// columns output.
|
||||
///
|
||||
/// There should always be at least one of these--there's no way to disable
|
||||
/// the time columns entirely (yet).
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub struct TimeTypes {
|
||||
pub accessed: bool,
|
||||
pub modified: bool,
|
||||
pub created: bool,
|
||||
}
|
||||
|
||||
impl Default for TimeTypes {
|
||||
|
||||
/// By default, display just the ‘modified’ time. This is the most
|
||||
/// common option, which is why it has this shorthand.
|
||||
fn default() -> TimeTypes {
|
||||
TimeTypes { accessed: false, modified: true, created: false }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// The **environment** struct contains any data that could change between
|
||||
@ -121,7 +316,7 @@ impl<'a, 'f> Table<'a> {
|
||||
}
|
||||
|
||||
fn display(&self, file: &File, column: &Column, xattrs: bool) -> TextCell {
|
||||
use output::column::TimeType::*;
|
||||
use output::table::TimeType::*;
|
||||
|
||||
match *column {
|
||||
Column::Permissions => self.permissions_plus(file, xattrs).render(&self.colours),
|
||||
|
Loading…
x
Reference in New Issue
Block a user