Selaa lähdekoodia

Merge pull request #159 from MakeNowJust/feature/classify

Implement -F/--classify option
Benjamin Sago 8 vuotta sitten
vanhempi
sitoutus
c205c3592b

+ 1 - 0
src/options/help.rs

@@ -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

+ 1 - 0
src/options/mod.rs

@@ -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)");

+ 8 - 0
src/options/view.rs

@@ -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))

+ 15 - 0
src/output/cell.rs

@@ -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))

+ 7 - 4
src/output/details.rs

@@ -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,
         }
         }
     }
     }

+ 4 - 3
src/output/grid.rs

@@ -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(())
         }
         }

+ 2 - 1
src/output/lines.rs

@@ -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(())
     }
     }

+ 13 - 1
src/output/mod.rs

@@ -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()