From 268b7d52dc0fbcd1a24ec04d403f56e36a321cb3 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Wed, 5 Jul 2017 20:16:04 +0100 Subject: [PATCH] Rename Columns to table::Options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/options/mod.rs | 10 +- src/options/view.rs | 14 +-- src/output/column.rs | 193 ----------------------------------- src/output/details.rs | 16 +-- src/output/grid_details.rs | 5 +- src/output/mod.rs | 3 +- src/output/render/size.rs | 4 +- src/output/table.rs | 201 ++++++++++++++++++++++++++++++++++++- 8 files changed, 223 insertions(+), 223 deletions(-) delete mode 100644 src/output/column.rs diff --git a/src/options/mod.rs b/src/options/mod.rs index fccc08c..a881476 100644 --- a/src/options/mod.rs +++ b/src/options/mod.rs @@ -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] diff --git a/src/options/view.rs b/src/options/view.rs index 349fda3..f0c7a07 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -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 { - Ok(Columns { +impl TableOptions { + fn deduce(matches: &getopts::Matches) -> Result { + Ok(TableOptions { size_format: SizeFormat::deduce(matches)?, time_types: TimeTypes::deduce(matches)?, inode: matches.opt_present("inode"), diff --git a/src/output/column.rs b/src/output/column.rs deleted file mode 100644 index 36a8511..0000000 --- a/src/output/column.rs +++ /dev/null @@ -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 { - 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 } - } -} diff --git a/src/output/details.rs b/src/output/details.rs index da78680..02587ff 100644 --- a/src/output/details.rs +++ b/src/output/details.rs @@ -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, + /// 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, /// Whether to show a header line or not. pub header: bool, @@ -139,7 +139,7 @@ impl<'a> Render<'a> { pub fn render(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); diff --git a/src/output/grid_details.rs b/src/output/grid_details.rs index 3d30cb0..bfa5d4e 100644 --- a/src/output/grid_details.rs +++ b/src/output/grid_details.rs @@ -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(&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(), }; diff --git a/src/output/mod.rs b/src/output/mod.rs index 1d0da6d..60ba961 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -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; diff --git a/src/output/render/size.rs b/src/output/render/size.rs index 7bde089..cd63c6f 100644 --- a/src/output/render/size.rs +++ b/src/output/render/size.rs @@ -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; diff --git a/src/output/table.rs b/src/output/table.rs index 6e5c80c..2893205 100644 --- a/src/output/table.rs +++ b/src/output/table.rs @@ -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 { + 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),