Implement -F/--classify option

This commit is contained in:
TSUYUSATO Kitsune 2017-04-13 20:47:44 +09:00
parent 3087565c01
commit e81b83b4ac
8 changed files with 51 additions and 9 deletions

View File

@ -7,6 +7,7 @@ DISPLAY OPTIONS
-R, --recurse recurse into directories -R, --recurse recurse into directories
-T, --tree recurse into subdirectories in a tree view -T, --tree recurse into subdirectories in a tree view
-x, --across sort multi-column view entries across -x, --across sort multi-column view entries across
-F, --classify show file type indicator (one of */=@|)
--color=WHEN, --colour=WHEN when to colourise the output (always, auto, never) --color=WHEN, --colour=WHEN when to colourise the output (always, auto, never)
--color-scale, --colour-scale colour file sizes according to their magnitude --color-scale, --colour-scale colour file sizes according to their magnitude

View File

@ -55,6 +55,7 @@ impl Options {
opts.optflag("R", "recurse", "recurse into directories"); opts.optflag("R", "recurse", "recurse into directories");
opts.optflag("T", "tree", "recurse into subdirectories in a tree view"); opts.optflag("T", "tree", "recurse into subdirectories in a tree view");
opts.optflag("x", "across", "sort multi-column view entries across"); opts.optflag("x", "across", "sort multi-column view entries across");
opts.optflag("F", "classify", "show file type indicator (one of */=@|)");
opts.optopt ("", "color", "when to show anything in colours", "WHEN"); opts.optopt ("", "color", "when to show anything in colours", "WHEN");
opts.optopt ("", "colour", "when to show anything in colours (alternate spelling)", "WHEN"); opts.optopt ("", "colour", "when to show anything in colours (alternate spelling)", "WHEN");
opts.optflag("", "color-scale", "use a colour scale when displaying file sizes (alternate spelling)"); opts.optflag("", "color-scale", "use a colour scale when displaying file sizes (alternate spelling)");

View File

@ -58,6 +58,7 @@ impl View {
filter: filter.clone(), filter: filter.clone(),
xattr: xattr::ENABLED && matches.opt_present("extended"), xattr: xattr::ENABLED && matches.opt_present("extended"),
colours: colours, colours: colours,
classify: matches.opt_present("classify"),
}; };
Ok(details) Ok(details)
@ -86,6 +87,8 @@ impl View {
}; };
let other_options_scan = || { let other_options_scan = || {
let classify = matches.opt_present("classify");
let term_colours = TerminalColours::deduce(matches)?; let term_colours = TerminalColours::deduce(matches)?;
let term_width = TerminalWidth::deduce()?; let term_width = TerminalWidth::deduce()?;
@ -103,6 +106,7 @@ impl View {
else { else {
let lines = Lines { let lines = Lines {
colours: colours, colours: colours,
classify: classify,
}; };
Ok(View::Lines(lines)) Ok(View::Lines(lines))
@ -116,6 +120,7 @@ impl View {
filter: filter.clone(), // TODO: clone filter: filter.clone(), // TODO: clone
xattr: false, xattr: false,
colours: colours, colours: colours,
classify: classify,
}; };
Ok(View::Details(details)) Ok(View::Details(details))
@ -125,6 +130,7 @@ impl View {
across: matches.opt_present("across"), across: matches.opt_present("across"),
console_width: width, console_width: width,
colours: colours, colours: colours,
classify: classify,
}; };
Ok(View::Grid(grid)) Ok(View::Grid(grid))
@ -148,6 +154,7 @@ impl View {
filter: filter.clone(), filter: filter.clone(),
xattr: false, xattr: false,
colours: colours, colours: colours,
classify: classify,
}; };
Ok(View::Details(details)) Ok(View::Details(details))
@ -155,6 +162,7 @@ impl View {
else { else {
let lines = Lines { let lines = Lines {
colours: colours, colours: colours,
classify: classify,
}; };
Ok(View::Lines(lines)) Ok(View::Lines(lines))

View File

@ -5,6 +5,8 @@ use std::ops::{Add, Deref, DerefMut};
use ansi_term::{Style, ANSIString, ANSIStrings}; use ansi_term::{Style, ANSIString, ANSIStrings};
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use fs::File;
/// An individual cell that holds text in a table, used in the details and /// An individual cell that holds text in a table, used in the details and
/// lines views to store ANSI-terminal-formatted data before it is printed. /// lines views to store ANSI-terminal-formatted data before it is printed.
@ -178,6 +180,19 @@ impl TextCellContents {
#[derive(PartialEq, Debug, Clone, Copy, Default)] #[derive(PartialEq, Debug, Clone, Copy, Default)]
pub struct DisplayWidth(usize); pub struct DisplayWidth(usize);
impl DisplayWidth {
pub fn from_file(file: &File, classify: bool) -> DisplayWidth {
let name_width = *DisplayWidth::from(&*file.name);
if classify {
if file.is_executable_file() || file.is_directory() ||
file.is_pipe() || file.is_link() || file.is_socket() {
return DisplayWidth(name_width + 1);
}
}
DisplayWidth(name_width)
}
}
impl<'a> From<&'a str> for DisplayWidth { impl<'a> From<&'a str> for DisplayWidth {
fn from(input: &'a str) -> DisplayWidth { fn from(input: &'a str) -> DisplayWidth {
DisplayWidth(UnicodeWidthStr::width(input)) DisplayWidth(UnicodeWidthStr::width(input))

View File

@ -140,6 +140,9 @@ pub struct Details {
/// The colours to use to display information in the table, including the /// The colours to use to display information in the table, including the
/// colour of the tree view symbols. /// colour of the tree view symbols.
pub colours: Colours, pub colours: Colours,
/// Whether to show a file type indiccator.
pub classify: bool,
} }
/// The **environment** struct contains any data that could change between /// The **environment** struct contains any data that could change between
@ -303,7 +306,7 @@ impl Details {
for (index, egg) in file_eggs.into_iter().enumerate() { for (index, egg) in file_eggs.into_iter().enumerate() {
let mut files = Vec::new(); let mut files = Vec::new();
let mut errors = egg.errors; let mut errors = egg.errors;
let mut width = DisplayWidth::from(&*egg.file.name); let mut width = DisplayWidth::from_file(&egg.file, self.classify);
if egg.file.dir.is_none() { if egg.file.dir.is_none() {
if let Some(parent) = egg.file.path.parent() { if let Some(parent) = egg.file.path.parent() {
@ -312,7 +315,7 @@ impl Details {
} }
let name = TextCell { let name = TextCell {
contents: filename(&egg.file, &self.colours, true), contents: filename(&egg.file, &self.colours, true, self.classify),
width: width, width: width,
}; };
@ -453,7 +456,7 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
} }
pub fn filename_cell(&self, file: File, links: bool) -> TextCell { pub fn filename_cell(&self, file: File, links: bool) -> TextCell {
let mut width = DisplayWidth::from(&*file.name); let mut width = DisplayWidth::from_file(&file, self.opts.classify);
if file.dir.is_none() { if file.dir.is_none() {
if let Some(parent) = file.path.parent() { if let Some(parent) = file.path.parent() {
@ -462,7 +465,7 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
} }
TextCell { TextCell {
contents: filename(&file, &self.opts.colours, links), contents: filename(&file, &self.opts.colours, links, self.opts.classify),
width: width, width: width,
} }
} }

View File

@ -13,6 +13,7 @@ pub struct Grid {
pub across: bool, pub across: bool,
pub console_width: usize, pub console_width: usize,
pub colours: Colours, pub colours: Colours,
pub classify: bool,
} }
impl Grid { impl Grid {
@ -28,7 +29,7 @@ impl Grid {
grid.reserve(files.len()); grid.reserve(files.len());
for file in files.iter() { for file in files.iter() {
let mut width = DisplayWidth::from(&*file.name); let mut width = DisplayWidth::from_file(file, self.classify);
if file.dir.is_none() { if file.dir.is_none() {
if let Some(parent) = file.path.parent() { if let Some(parent) = file.path.parent() {
@ -37,7 +38,7 @@ impl Grid {
} }
grid.add(grid::Cell { grid.add(grid::Cell {
contents: filename(file, &self.colours, false).strings().to_string(), contents: filename(file, &self.colours, false, self.classify).strings().to_string(),
width: *width, width: *width,
}); });
} }
@ -48,7 +49,7 @@ impl Grid {
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 files.iter() { for file in files.iter() {
writeln!(w, "{}", filename(file, &self.colours, false).strings())?; writeln!(w, "{}", filename(file, &self.colours, false, self.classify).strings())?;
} }
Ok(()) Ok(())
} }

View File

@ -11,13 +11,14 @@ use super::colours::Colours;
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Lines { pub struct Lines {
pub colours: Colours, pub colours: Colours,
pub classify: bool,
} }
/// The lines view literally just displays each file, line-by-line. /// The lines view literally just displays each file, line-by-line.
impl Lines { impl Lines {
pub fn view<W: Write>(&self, files: Vec<File>, w: &mut W) -> IOResult<()> { pub fn view<W: Write>(&self, files: Vec<File>, w: &mut W) -> IOResult<()> {
for file in files { for file in files {
writeln!(w, "{}", ANSIStrings(&filename(&file, &self.colours, true)))?; writeln!(w, "{}", ANSIStrings(&filename(&file, &self.colours, true, self.classify)))?;
} }
Ok(()) Ok(())
} }

View File

@ -19,7 +19,7 @@ mod colours;
mod tree; mod tree;
pub fn filename(file: &File, colours: &Colours, links: bool) -> TextCellContents { pub fn filename(file: &File, colours: &Colours, links: bool, classify: bool) -> TextCellContents {
let mut bits = Vec::new(); let mut bits = Vec::new();
if file.dir.is_none() { if file.dir.is_none() {
@ -78,6 +78,18 @@ pub fn filename(file: &File, colours: &Colours, links: bool) -> TextCellContents
// Do nothing -- the error gets displayed on the next line // Do nothing -- the error gets displayed on the next line
} }
} }
} else if classify {
if file.is_executable_file() {
bits.push(Style::default().paint("*"));
} else if file.is_directory() {
bits.push(Style::default().paint("/"));
} else if file.is_pipe() {
bits.push(Style::default().paint("|"));
} else if file.is_link() {
bits.push(Style::default().paint("@"));
} else if file.is_socket() {
bits.push(Style::default().paint("="));
}
} }
bits.into() bits.into()