Replace FileName::new with a factory

The new FileStyles value will contain all the fields necessary to “style” a file’s name. Right now this is only the Classify field, but there can be more later. The benefit of this is that when we add more, we won’t need to update all the places where file names are displayed.
This commit is contained in:
Benjamin Sago 2017-07-08 12:11:11 +01:00
parent 8dd9df2e86
commit 0d613652a7
7 changed files with 97 additions and 70 deletions

View File

@ -168,13 +168,13 @@ impl<'w, W: Write + 'w> Exa<'w, W> {
/// printing differently... /// printing differently...
fn print_files(&mut self, dir: Option<&Dir>, files: Vec<File>) -> IOResult<()> { fn print_files(&mut self, dir: Option<&Dir>, files: Vec<File>) -> IOResult<()> {
if !files.is_empty() { if !files.is_empty() {
let View { ref mode, ref colours, classify } = self.options.view; let View { ref mode, ref colours, ref style } = self.options.view;
match *mode { match *mode {
Mode::Lines => lines::Render { files, colours, classify }.render(self.writer), Mode::Lines => lines::Render { files, colours, style }.render(self.writer),
Mode::Grid(ref opts) => grid::Render { files, colours, classify, opts }.render(self.writer), Mode::Grid(ref opts) => grid::Render { files, colours, style, opts }.render(self.writer),
Mode::Details(ref opts) => details::Render { dir, files, colours, classify, opts, filter: &self.options.filter, recurse: self.options.dir_action.recurse_options() }.render(self.writer), Mode::Details(ref opts) => details::Render { dir, files, colours, style, opts, filter: &self.options.filter, recurse: self.options.dir_action.recurse_options() }.render(self.writer),
Mode::GridDetails(ref grid, ref details) => grid_details::Render { dir, files, colours, classify, grid, details, filter: &self.options.filter }.render(self.writer), Mode::GridDetails(ref grid, ref details) => grid_details::Render { dir, files, colours, style, grid, details, filter: &self.options.filter }.render(self.writer),
} }
} }
else { else {

View File

@ -5,7 +5,7 @@ use getopts;
use output::Colours; use output::Colours;
use output::{grid, details}; use output::{grid, details};
use output::table::{TimeTypes, Environment, SizeFormat, Options as TableOptions}; use output::table::{TimeTypes, Environment, SizeFormat, Options as TableOptions};
use output::file_name::Classify; use output::file_name::{Classify, FileStyle};
use output::time::TimeFormat; use output::time::TimeFormat;
use options::Misfire; use options::Misfire;
use fs::feature::xattr; use fs::feature::xattr;
@ -16,7 +16,7 @@ use fs::feature::xattr;
pub struct View { pub struct View {
pub mode: Mode, pub mode: Mode,
pub colours: Colours, pub colours: Colours,
pub classify: Classify, pub style: FileStyle,
} }
impl View { impl View {
@ -25,8 +25,8 @@ impl View {
pub fn deduce(matches: &getopts::Matches) -> Result<View, Misfire> { pub fn deduce(matches: &getopts::Matches) -> Result<View, Misfire> {
let mode = Mode::deduce(matches)?; let mode = Mode::deduce(matches)?;
let colours = Colours::deduce(matches)?; let colours = Colours::deduce(matches)?;
let classify = Classify::deduce(matches); let style = FileStyle::deduce(matches);
Ok(View { mode, colours, classify }) Ok(View { mode, colours, style })
} }
} }
@ -370,6 +370,14 @@ impl Colours {
impl FileStyle {
fn deduce(matches: &getopts::Matches) -> FileStyle {
let classify = Classify::deduce(matches);
FileStyle { classify }
}
}
impl Classify { impl Classify {
fn deduce(matches: &getopts::Matches) -> Classify { fn deduce(matches: &getopts::Matches) -> Classify {
if matches.opt_present("classify") { Classify::AddFileIndicators } if matches.opt_present("classify") { Classify::AddFileIndicators }

View File

@ -70,7 +70,7 @@ use options::{FileFilter, RecurseOptions};
use output::colours::Colours; use output::colours::Colours;
use output::cell::TextCell; use output::cell::TextCell;
use output::tree::{TreeTrunk, TreeParams, TreeDepth}; use output::tree::{TreeTrunk, TreeParams, TreeDepth};
use output::file_name::{FileName, LinkStyle, Classify}; use output::file_name::{FileStyle, LinkStyle};
use output::table::{Table, Options as TableOptions, Row as TableRow}; use output::table::{Table, Options as TableOptions, Row as TableRow};
@ -107,7 +107,7 @@ pub struct Render<'a> {
pub dir: Option<&'a Dir>, pub dir: Option<&'a Dir>,
pub files: Vec<File<'a>>, pub files: Vec<File<'a>>,
pub colours: &'a Colours, pub colours: &'a Colours,
pub classify: Classify, pub style: &'a FileStyle,
pub opts: &'a Options, pub opts: &'a Options,
/// Whether to recurse through directories with a tree view, and if so, /// Whether to recurse through directories with a tree view, and if so,
@ -233,7 +233,7 @@ impl<'a> Render<'a> {
let row = Row { let row = Row {
tree: tree_params, tree: tree_params,
cells: egg.table_row, cells: egg.table_row,
name: FileName::new(&egg.file, LinkStyle::FullLinkPaths, self.classify, self.colours).paint().promote(), name: self.style.for_file(&egg.file, LinkStyle::FullLinkPaths, self.colours).paint().promote(),
}; };
rows.push(row); rows.push(row);

View File

@ -8,6 +8,62 @@ use output::escape;
use output::cell::TextCellContents; use output::cell::TextCellContents;
/// Basically a file name factory.
#[derive(PartialEq, Debug)]
pub struct FileStyle {
/// Whether to append file class characters to file names.
pub classify: Classify,
}
impl FileStyle {
/// Create a new `FileName` that prints the given files name, painting it
/// with the remaining arguments.
pub fn for_file<'a, 'dir>(&self, file: &'a File<'dir>, link_style: LinkStyle, colours: &'a Colours) -> FileName<'a, 'dir> {
let target = if file.is_link() { Some(file.link_target()) }
else { None };
FileName { file, colours, target, link_style, classify: self.classify }
}
}
/// When displaying a file name, there needs to be some way to handle broken
/// links, depending on how long the resulting Cell can be.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum LinkStyle {
/// Just display the file names, but colour them differently if theyre
/// a broken link or cant be followed.
JustFilenames,
/// Display all files in their usual style, but follow each link with an
/// arrow pointing to their path, colouring the path differently if its
/// a broken link, and doing nothing if it cant be followed.
FullLinkPaths,
}
/// Whether to append file class characters to the file names.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Classify {
/// Just display the file names, without any characters.
JustFilenames,
/// Add a character after the file name depending on what class of file
/// it is.
AddFileIndicators,
}
impl Default for Classify {
fn default() -> Classify {
Classify::JustFilenames
}
}
/// A **file name** holds all the information necessary to display the name /// A **file name** holds all the information necessary to display the name
/// of the given file. This is used in all of the views. /// of the given file. This is used in all of the views.
pub struct FileName<'a, 'dir: 'a> { pub struct FileName<'a, 'dir: 'a> {
@ -31,15 +87,6 @@ pub struct FileName<'a, 'dir: 'a> {
impl<'a, 'dir> FileName<'a, 'dir> { impl<'a, 'dir> FileName<'a, 'dir> {
/// Create a new `FileName` that prints the given files name, painting it
/// with the remaining arguments.
pub fn new(file: &'a File<'dir>, link_style: LinkStyle, classify: Classify, colours: &'a Colours) -> FileName<'a, 'dir> {
let target = if file.is_link() { Some(file.link_target()) }
else { None };
FileName { file, colours, target, link_style, classify }
}
/// Paints the name of the file using the colours, resulting in a vector /// Paints the name of the file using the colours, resulting in a vector
/// of coloured cells that can be printed to the terminal. /// of coloured cells that can be printed to the terminal.
/// ///
@ -73,7 +120,14 @@ impl<'a, 'dir> FileName<'a, 'dir> {
} }
if !target.name.is_empty() { if !target.name.is_empty() {
let target = FileName::new(target, LinkStyle::FullLinkPaths, Classify::JustFilenames, self.colours); let target = FileName {
file: target,
colours: self.colours,
target: None,
link_style: LinkStyle::FullLinkPaths,
classify: Classify::JustFilenames,
};
for bit in target.coloured_file_name() { for bit in target.coloured_file_name() {
bits.push(bit); bits.push(bit);
} }
@ -195,38 +249,3 @@ impl<'a, 'dir> FileName<'a, 'dir> {
} }
} }
} }
/// When displaying a file name, there needs to be some way to handle broken
/// links, depending on how long the resulting Cell can be.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum LinkStyle {
/// Just display the file names, but colour them differently if theyre
/// a broken link or cant be followed.
JustFilenames,
/// Display all files in their usual style, but follow each link with an
/// arrow pointing to their path, colouring the path differently if its
/// a broken link, and doing nothing if it cant be followed.
FullLinkPaths,
}
/// Whether to append file class characters to the file names.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Classify {
/// Just display the file names, without any characters.
JustFilenames,
/// Add a character after the file name depending on what class of file
/// it is.
AddFileIndicators,
}
impl Default for Classify {
fn default() -> Classify {
Classify::JustFilenames
}
}

View File

@ -4,7 +4,7 @@ use term_grid as tg;
use fs::File; use fs::File;
use output::colours::Colours; use output::colours::Colours;
use output::file_name::{FileName, LinkStyle, Classify}; use output::file_name::{FileStyle, LinkStyle};
#[derive(PartialEq, Debug, Copy, Clone)] #[derive(PartialEq, Debug, Copy, Clone)]
@ -24,7 +24,7 @@ impl Options {
pub struct Render<'a> { pub struct Render<'a> {
pub files: Vec<File<'a>>, pub files: Vec<File<'a>>,
pub colours: &'a Colours, pub colours: &'a Colours,
pub classify: Classify, pub style: &'a FileStyle,
pub opts: &'a Options, pub opts: &'a Options,
} }
@ -38,7 +38,7 @@ impl<'a> Render<'a> {
grid.reserve(self.files.len()); grid.reserve(self.files.len());
for file in self.files.iter() { for file in self.files.iter() {
let filename = FileName::new(file, LinkStyle::JustFilenames, self.classify, self.colours).paint(); let filename = self.style.for_file(file, LinkStyle::JustFilenames, self.colours).paint();
let width = filename.width(); let width = filename.width();
grid.add(tg::Cell { grid.add(tg::Cell {
@ -53,7 +53,7 @@ impl<'a> Render<'a> {
else { else {
// File names too long for a grid - drop down to just listing them! // File names too long for a grid - drop down to just listing them!
for file in self.files.iter() { for file in self.files.iter() {
let name_cell = FileName::new(file, LinkStyle::JustFilenames, self.classify, self.colours).paint(); let name_cell = self.style.for_file(file, LinkStyle::JustFilenames, self.colours).paint();
writeln!(w, "{}", name_cell.strings())?; writeln!(w, "{}", name_cell.strings())?;
} }
Ok(()) Ok(())

View File

@ -11,7 +11,7 @@ use output::cell::TextCell;
use output::colours::Colours; use output::colours::Colours;
use output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender}; use output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
use output::grid::Options as GridOptions; use output::grid::Options as GridOptions;
use output::file_name::{FileName, LinkStyle, Classify}; use output::file_name::{FileStyle, LinkStyle};
use output::table::{Table, Row as TableRow, Options as TableOptions}; use output::table::{Table, Row as TableRow, Options as TableOptions};
use output::tree::{TreeParams, TreeDepth}; use output::tree::{TreeParams, TreeDepth};
@ -20,7 +20,7 @@ pub struct Render<'a> {
pub dir: Option<&'a Dir>, pub dir: Option<&'a Dir>,
pub files: Vec<File<'a>>, pub files: Vec<File<'a>>,
pub colours: &'a Colours, pub colours: &'a Colours,
pub classify: Classify, pub style: &'a FileStyle,
pub grid: &'a GridOptions, pub grid: &'a GridOptions,
pub details: &'a DetailsOptions, pub details: &'a DetailsOptions,
pub filter: &'a FileFilter, pub filter: &'a FileFilter,
@ -32,7 +32,7 @@ impl<'a> Render<'a> {
dir: self.dir.clone(), dir: self.dir.clone(),
files: Vec::new(), files: Vec::new(),
colours: self.colours, colours: self.colours,
classify: self.classify, style: self.style,
opts: self.details, opts: self.details,
recurse: None, recurse: None,
filter: self.filter, filter: self.filter,
@ -52,7 +52,7 @@ impl<'a> Render<'a> {
.collect::<Vec<TableRow>>(); .collect::<Vec<TableRow>>();
let file_names = self.files.iter() let file_names = self.files.iter()
.map(|file| FileName::new(file, LinkStyle::JustFilenames, self.classify, self.colours).paint().promote()) .map(|file| self.style.for_file(file, LinkStyle::JustFilenames, self.colours).paint().promote())
.collect::<Vec<TextCell>>(); .collect::<Vec<TextCell>>();
let mut last_working_table = self.make_grid(1, options, &file_names, rows.clone(), &drender); let mut last_working_table = self.make_grid(1, options, &file_names, rows.clone(), &drender);

View File

@ -4,7 +4,7 @@ use ansi_term::ANSIStrings;
use fs::File; use fs::File;
use output::file_name::{FileName, LinkStyle, Classify}; use output::file_name::{FileName, FileStyle, LinkStyle};
use super::colours::Colours; use super::colours::Colours;
@ -12,7 +12,7 @@ use super::colours::Colours;
pub struct Render<'a> { pub struct Render<'a> {
pub files: Vec<File<'a>>, pub files: Vec<File<'a>>,
pub colours: &'a Colours, pub colours: &'a Colours,
pub classify: Classify, pub style: &'a FileStyle,
} }
impl<'a> Render<'a> { impl<'a> Render<'a> {
@ -26,6 +26,6 @@ impl<'a> Render<'a> {
} }
fn render_file<'f>(&self, file: &'f File<'a>) -> FileName<'f, 'a> { fn render_file<'f>(&self, file: &'f File<'a>) -> FileName<'f, 'a> {
FileName::new(file, LinkStyle::FullLinkPaths, self.classify, self.colours) self.style.for_file(file, LinkStyle::FullLinkPaths, self.colours)
} }
} }