1
0
Chester Liu 4 жил өмнө
parent
commit
0e8a4582d0
4 өөрчлөгдсөн 197 нэмэгдсэн , 176 устгасан
  1. 78 67
      src/fs/file.rs
  2. 17 8
      src/fs/filter.rs
  3. 88 99
      src/options/parser.rs
  4. 14 2
      src/output/table.rs

+ 78 - 67
src/fs/file.rs

@@ -71,21 +71,14 @@ impl<'dir> File<'dir> {
           FN: Into<Option<String>>
     {
         let parent_dir = parent_dir.into();
-        let name = filename.into().unwrap_or_else(|| File::filename(&path));
-        let ext = File::ext(&path);
+        let name       = filename.into().unwrap_or_else(|| File::filename(&path));
+        let ext        = File::ext(&path);
 
         debug!("Statting file {:?}", &path);
-        let metadata = std::fs::symlink_metadata(&path)?;
+        let metadata   = std::fs::symlink_metadata(&path)?;
         let is_all_all = false;
 
-        Ok(File {
-            path,
-            parent_dir,
-            metadata,
-            ext,
-            name,
-            is_all_all,
-        })
+        Ok(File { path, parent_dir, metadata, ext, name, is_all_all })
     }
 
     pub fn new_aa_current(parent_dir: &'dir Dir) -> io::Result<File<'dir>> {
@@ -93,7 +86,7 @@ impl<'dir> File<'dir> {
         let ext        = File::ext(&path);
 
         debug!("Statting file {:?}", &path);
-        let metadata = std::fs::symlink_metadata(&path)?;
+        let metadata   = std::fs::symlink_metadata(&path)?;
         let is_all_all = true;
         let parent_dir = Some(parent_dir);
 
@@ -116,12 +109,9 @@ impl<'dir> File<'dir> {
     /// use the last component as the name.
     pub fn filename(path: &Path) -> String {
         if let Some(back) = path.components().next_back() {
-            let name = back.as_os_str().to_string_lossy().to_string();
-            #[cfg(unix)]
-            return name;
-            #[cfg(windows)]
-            return name;
-        } else {
+            back.as_os_str().to_string_lossy().to_string()
+        }
+        else {
             // use the path as fallback
             error!("Path {:?} has no last component", path);
             path.display().to_string()
@@ -225,11 +215,14 @@ impl<'dir> File<'dir> {
     fn reorient_target_path(&self, path: &Path) -> PathBuf {
         if path.is_absolute() {
             path.to_path_buf()
-        } else if let Some(dir) = self.parent_dir {
+        }
+        else if let Some(dir) = self.parent_dir {
             dir.join(&*path)
-        } else if let Some(parent) = self.path.parent() {
+        }
+        else if let Some(parent) = self.path.parent() {
             parent.join(&*path)
-        } else {
+        }
+        else {
             self.path.join(&*path)
         }
     }
@@ -245,14 +238,15 @@ impl<'dir> File<'dir> {
     /// existed. If this file cannot be read at all, returns the error that
     /// we got when we tried to read it.
     pub fn link_target(&self) -> FileTarget<'dir> {
+
         // We need to be careful to treat the path actually pointed to by
         // this file — which could be absolute or relative — to the path
         // we actually look up and turn into a `File` — which needs to be
         // absolute to be accessible from any directory.
         debug!("Reading link {:?}", &self.path);
         let path = match std::fs::read_link(&self.path) {
-            Ok(p) => p,
-            Err(e) => return FileTarget::Err(e),
+            Ok(p)   => p,
+            Err(e)  => return FileTarget::Err(e),
         };
 
         let absolute_path = self.reorient_target_path(&path);
@@ -261,7 +255,7 @@ impl<'dir> File<'dir> {
         // follow links.
         match std::fs::metadata(&absolute_path) {
             Ok(metadata) => {
-                let ext = File::ext(&path);
+                let ext  = File::ext(&path);
                 let name = File::filename(&path);
                 let file = File { parent_dir: None, path, ext, metadata, name, is_all_all: false };
                 FileTarget::Ok(Box::new(file))
@@ -303,7 +297,8 @@ impl<'dir> File<'dir> {
     pub fn blocks(&self) -> f::Blocks {
         if self.is_file() || self.is_link() {
             f::Blocks::Some(self.metadata.blocks())
-        } else {
+        }
+        else {
             f::Blocks::None
         }
     }
@@ -330,19 +325,19 @@ impl<'dir> File<'dir> {
     /// usually just have a file size of zero.
     pub fn size(&self) -> f::Size {
         if self.is_directory() {
-            return f::Size::None;
-        };
+            f::Size::None
+        }
         #[cfg(unix)]
-        {
-            if self.is_char_device() || self.is_block_device() {
-                let dev = self.metadata.rdev();
-                return f::Size::DeviceIDs(f::DeviceIDs {
-                    major: (dev / 256) as u8,
-                    minor: (dev % 256) as u8,
-                });
-            };
+        else if self.is_char_device() || self.is_block_device() {
+            let dev = self.metadata.rdev();
+            f::Size::DeviceIDs(f::DeviceIDs {
+                major: (dev / 256) as u8,
+                minor: (dev % 256) as u8,
+            })
+        }
+        else {
+            f::Size::Some(self.metadata.len())
         }
-        return f::Size::Some(self.metadata.len());
     }
 
     /// This file’s last modified timestamp, if available on this platform.
@@ -389,9 +384,11 @@ impl<'dir> File<'dir> {
     pub fn type_char(&self) -> f::Type {
         if self.is_file() {
             f::Type::File
-        } else if self.is_directory() {
+        }
+        else if self.is_directory() {
             f::Type::Directory
-        } else {
+        }
+        else {
             f::Type::Special
         }
     }
@@ -399,19 +396,26 @@ impl<'dir> File<'dir> {
     pub fn type_char(&self) -> f::Type {
         if self.is_file() {
             f::Type::File
-        } else if self.is_directory() {
+        }
+        else if self.is_directory() {
             f::Type::Directory
-        } else if self.is_pipe() {
+        }
+        else if self.is_pipe() {
             f::Type::Pipe
-        } else if self.is_link() {
+        }
+        else if self.is_link() {
             f::Type::Link
-        } else if self.is_char_device() {
+        }
+        else if self.is_char_device() {
             f::Type::CharDevice
-        } else if self.is_block_device() {
+        }
+        else if self.is_block_device() {
             f::Type::BlockDevice
-        } else if self.is_socket() {
+        }
+        else if self.is_socket() {
             f::Type::Socket
-        } else {
+        }
+        else {
             f::Type::Special
         }
     }
@@ -423,21 +427,21 @@ impl<'dir> File<'dir> {
         let has_bit = |bit| bits & bit == bit;
 
         f::Permissions {
-            user_read: has_bit(modes::USER_READ),
-            user_write: has_bit(modes::USER_WRITE),
-            user_execute: has_bit(modes::USER_EXECUTE),
+            user_read:      has_bit(modes::USER_READ),
+            user_write:     has_bit(modes::USER_WRITE),
+            user_execute:   has_bit(modes::USER_EXECUTE),
 
-            group_read: has_bit(modes::GROUP_READ),
-            group_write: has_bit(modes::GROUP_WRITE),
-            group_execute: has_bit(modes::GROUP_EXECUTE),
+            group_read:     has_bit(modes::GROUP_READ),
+            group_write:    has_bit(modes::GROUP_WRITE),
+            group_execute:  has_bit(modes::GROUP_EXECUTE),
 
-            other_read: has_bit(modes::OTHER_READ),
-            other_write: has_bit(modes::OTHER_WRITE),
-            other_execute: has_bit(modes::OTHER_EXECUTE),
+            other_read:     has_bit(modes::OTHER_READ),
+            other_write:    has_bit(modes::OTHER_WRITE),
+            other_execute:  has_bit(modes::OTHER_EXECUTE),
 
-            sticky: has_bit(modes::STICKY),
-            setgid: has_bit(modes::SETGID),
-            setuid: has_bit(modes::SETUID),
+            sticky:         has_bit(modes::STICKY),
+            setgid:         has_bit(modes::SETGID),
+            setuid:         has_bit(modes::SETUID),
         }
     }
 
@@ -458,14 +462,17 @@ impl<'dir> File<'dir> {
     }
 }
 
+
 impl<'a> AsRef<File<'a>> for File<'a> {
     fn as_ref(&self) -> &File<'a> {
         self
     }
 }
 
+
 /// The result of following a symlink.
 pub enum FileTarget<'dir> {
+
     /// The symlink pointed at a file that exists.
     Ok(Box<File<'dir>>),
 
@@ -484,6 +491,7 @@ pub enum FileTarget<'dir> {
 }
 
 impl<'dir> FileTarget<'dir> {
+
     /// Whether this link doesn’t lead to a file, for whatever reason. This
     /// gets used to determine how to highlight the link in grid views.
     pub fn is_broken(&self) -> bool {
@@ -491,6 +499,7 @@ impl<'dir> FileTarget<'dir> {
     }
 }
 
+
 /// More readable aliases for the permission bits exposed by libc.
 #[allow(trivial_numeric_casts)]
 #[cfg(unix)]
@@ -500,23 +509,24 @@ mod modes {
     // from `metadata.permissions().mode()` is always `u32`.
     pub type Mode = u32;
 
-    pub const USER_READ: Mode = libc::S_IRUSR as Mode;
-    pub const USER_WRITE: Mode = libc::S_IWUSR as Mode;
-    pub const USER_EXECUTE: Mode = libc::S_IXUSR as Mode;
+    pub const USER_READ: Mode     = libc::S_IRUSR as Mode;
+    pub const USER_WRITE: Mode    = libc::S_IWUSR as Mode;
+    pub const USER_EXECUTE: Mode  = libc::S_IXUSR as Mode;
 
-    pub const GROUP_READ: Mode = libc::S_IRGRP as Mode;
-    pub const GROUP_WRITE: Mode = libc::S_IWGRP as Mode;
+    pub const GROUP_READ: Mode    = libc::S_IRGRP as Mode;
+    pub const GROUP_WRITE: Mode   = libc::S_IWGRP as Mode;
     pub const GROUP_EXECUTE: Mode = libc::S_IXGRP as Mode;
 
-    pub const OTHER_READ: Mode = libc::S_IROTH as Mode;
-    pub const OTHER_WRITE: Mode = libc::S_IWOTH as Mode;
+    pub const OTHER_READ: Mode    = libc::S_IROTH as Mode;
+    pub const OTHER_WRITE: Mode   = libc::S_IWOTH as Mode;
     pub const OTHER_EXECUTE: Mode = libc::S_IXOTH as Mode;
 
-    pub const STICKY: Mode = libc::S_ISVTX as Mode;
-    pub const SETGID: Mode = libc::S_ISGID as Mode;
-    pub const SETUID: Mode = libc::S_ISUID as Mode;
+    pub const STICKY: Mode        = libc::S_ISVTX as Mode;
+    pub const SETGID: Mode        = libc::S_ISGID as Mode;
+    pub const SETUID: Mode        = libc::S_ISUID as Mode;
 }
 
+
 #[cfg(test)]
 mod ext_test {
     use super::File;
@@ -538,6 +548,7 @@ mod ext_test {
     }
 }
 
+
 #[cfg(test)]
 mod filename_test {
     use super::File;

+ 17 - 8
src/fs/filter.rs

@@ -26,6 +26,7 @@ use crate::fs::File;
 /// performing the comparison.
 #[derive(PartialEq, Debug, Clone)]
 pub struct FileFilter {
+
     /// Whether directories should be listed first, and other types of file
     /// second. Some users prefer it like this.
     pub list_dirs_first: bool,
@@ -137,9 +138,11 @@ impl FileFilter {
     }
 }
 
+
 /// User-supplied field to sort by.
 #[derive(PartialEq, Debug, Copy, Clone)]
 pub enum SortField {
+
     /// Don’t apply any sorting. This is usually used as an optimisation in
     /// scripts, where the order doesn’t matter.
     Unsorted,
@@ -221,6 +224,7 @@ pub enum SortField {
 /// effects they have.
 #[derive(PartialEq, Debug, Copy, Clone)]
 pub enum SortCase {
+
     /// Sort files case-sensitively with uppercase first, with ‘A’ coming
     /// before ‘a’.
     ABCabc,
@@ -230,6 +234,7 @@ pub enum SortCase {
 }
 
 impl SortField {
+
     /// Compares two files to determine the order they should be listed in,
     /// depending on the search field.
     ///
@@ -289,6 +294,7 @@ impl SortField {
     }
 }
 
+
 /// The **ignore patterns** are a list of globs that are tested against
 /// each filename, and if any of them match, that file isn’t displayed.
 /// This lets a user hide, say, text files by ignoring `*.txt`.
@@ -308,6 +314,7 @@ impl FromIterator<glob::Pattern> for IgnorePatterns {
 }
 
 impl IgnorePatterns {
+
     /// Create a new list from the input glob strings, turning the inputs that
     /// are valid glob patterns into an `IgnorePatterns`. The inputs that
     /// don’t parse correctly are returned separately.
@@ -317,8 +324,8 @@ impl IgnorePatterns {
         // Almost all glob patterns are valid, so it’s worth pre-allocating
         // the vector with enough space for all of them.
         let mut patterns = match iter.size_hint() {
-            (_, Some(count)) => Vec::with_capacity(count),
-            _ => Vec::new(),
+            (_, Some(count))  => Vec::with_capacity(count),
+             _                => Vec::new(),
         };
 
         // Similarly, assume there won’t be any errors.
@@ -327,7 +334,7 @@ impl IgnorePatterns {
         for input in iter {
             match glob::Pattern::new(input) {
                 Ok(pat) => patterns.push(pat),
-                Err(e) => errors.push(e),
+                Err(e)  => errors.push(e),
             }
         }
 
@@ -353,9 +360,11 @@ impl IgnorePatterns {
     // isn’t probably means it’s in the wrong place
 }
 
+
 /// Whether to ignore or display files that are mentioned in `.gitignore` files.
 #[derive(PartialEq, Debug, Copy, Clone)]
 pub enum GitIgnore {
+
     /// Ignore files that Git would ignore. This means doing a check for a
     /// `.gitignore` file, possibly recursively up the filesystem tree.
     CheckAndIgnore,
@@ -384,23 +393,23 @@ mod test_ignores {
 
     #[test]
     fn ignores_a_glob() {
-        let (pats, fails) = IgnorePatterns::parse_from_iter(vec!["*.mp3"]);
+        let (pats, fails) = IgnorePatterns::parse_from_iter(vec![ "*.mp3" ]);
         assert!(fails.is_empty());
         assert_eq!(false, pats.is_ignored("nothing"));
-        assert_eq!(true, pats.is_ignored("test.mp3"));
+        assert_eq!(true,  pats.is_ignored("test.mp3"));
     }
 
     #[test]
     fn ignores_an_exact_filename() {
-        let (pats, fails) = IgnorePatterns::parse_from_iter(vec!["nothing"]);
+        let (pats, fails) = IgnorePatterns::parse_from_iter(vec![ "nothing" ]);
         assert!(fails.is_empty());
-        assert_eq!(true, pats.is_ignored("nothing"));
+        assert_eq!(true,  pats.is_ignored("nothing"));
         assert_eq!(false, pats.is_ignored("test.mp3"));
     }
 
     #[test]
     fn ignores_both() {
-        let (pats, fails) = IgnorePatterns::parse_from_iter(vec!["nothing", "*.mp3"]);
+        let (pats, fails) = IgnorePatterns::parse_from_iter(vec![ "nothing", "*.mp3" ]);
         assert!(fails.is_empty());
         assert_eq!(true, pats.is_ignored("nothing"));
         assert_eq!(true, pats.is_ignored("test.mp3"));

+ 88 - 99
src/options/parser.rs

@@ -27,7 +27,7 @@
 //! command-line options, as all the options and their values (such as
 //! `--sort size`) are guaranteed to just be 8-bit ASCII.
 
-use std::borrow::Cow;
+
 use std::ffi::{OsStr, OsString};
 use std::fmt;
 
@@ -79,6 +79,7 @@ impl fmt::Display for Flag {
 /// Whether redundant arguments should be considered a problem.
 #[derive(PartialEq, Debug, Copy, Clone)]
 pub enum Strictness {
+
     /// Throw an error when an argument doesn’t do anything, either because
     /// it requires another argument to be specified, or because two conflict.
     ComplainAboutRedundantArguments,
@@ -92,6 +93,7 @@ pub enum Strictness {
 /// arguments.
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum TakesValue {
+
     /// This flag has to be followed by a value.
     /// If there’s a fixed set of possible values, they can be printed out
     /// with the error text.
@@ -104,9 +106,11 @@ pub enum TakesValue {
     Optional(Option<Values>),
 }
 
+
 /// An **argument** can be matched by one of the user’s input strings.
 #[derive(PartialEq, Debug, Copy, Clone)]
 pub struct Arg {
+
     /// The short argument that matches it, if any.
     pub short: Option<ShortArg>,
 
@@ -130,20 +134,19 @@ impl fmt::Display for Arg {
     }
 }
 
+
 /// Literally just several args.
 #[derive(PartialEq, Debug)]
 pub struct Args(pub &'static [&'static Arg]);
 
 impl Args {
+
     /// Iterates over the given list of command-line arguments and parses
     /// them into a list of matched flags and free strings.
     pub fn parse<'args, I>(&self, inputs: I, strictness: Strictness) -> Result<Matches<'args>, ParseError>
     where I: IntoIterator<Item = &'args OsStr>
     {
-        #[cfg(unix)]
         use std::os::unix::ffi::OsStrExt;
-        #[cfg(windows)]
-        use os_str_bytes::{OsStrBytes, OsStringBytes};
 
         let mut parsing = true;
 
@@ -156,7 +159,7 @@ impl Args {
         // doesn’t have one in its string so it needs the next one.
         let mut inputs = inputs.into_iter();
         while let Some(arg) = inputs.next() {
-            let bytes = arg.to_bytes();
+            let bytes = arg.as_bytes();
 
             // Stop parsing if one of the arguments is the literal string “--”.
             // This allows a file named “--arg” to be specified by passing in
@@ -164,18 +167,20 @@ impl Args {
             // doesn’t exist.
             if ! parsing {
                 frees.push(arg)
-            } else if arg == "--" {
+            }
+            else if arg == "--" {
                 parsing = false;
             }
+
             // If the string starts with *two* dashes then it’s a long argument.
             else if bytes.starts_with(b"--") {
-                let long_arg_name = OsStrBytes::from_bytes(&bytes[2..]).unwrap();
+                let long_arg_name = OsStr::from_bytes(&bytes[2..]);
 
                 // If there’s an equals in it, then the string before the
                 // equals will be the flag’s name, and the string after it
                 // will be its value.
-                if let Some((before, after)) = split_on_equals(&long_arg_name) {
-                    let arg = self.lookup_long(&*before)?;
+                if let Some((before, after)) = split_on_equals(long_arg_name) {
+                    let arg = self.lookup_long(before)?;
                     let flag = Flag::Long(arg.long);
                     match arg.takes_value {
                         TakesValue::Necessary(_) |
@@ -183,10 +188,11 @@ impl Args {
                         TakesValue::Forbidden    => return Err(ParseError::ForbiddenValue { flag }),
                     }
                 }
+
                 // If there’s no equals, then the entire string (apart from
                 // the dashes) is the argument name.
                 else {
-                    let arg = self.lookup_long(&*long_arg_name)?;
+                    let arg = self.lookup_long(long_arg_name)?;
                     let flag = Flag::Long(arg.long);
                     match arg.takes_value {
                         TakesValue::Forbidden => {
@@ -194,25 +200,28 @@ impl Args {
                         }
                         TakesValue::Necessary(values) => {
                             if let Some(next_arg) = inputs.next() {
-                                result_flags.push((flag, Some(next_arg.clone())));
-                            } else {
-                                return Err(ParseError::NeedsValue { flag, values });
+                                result_flags.push((flag, Some(next_arg)));
+                            }
+                            else {
+                                return Err(ParseError::NeedsValue { flag, values })
                             }
                         }
                         TakesValue::Optional(_) => {
                             if let Some(next_arg) = inputs.next() {
-                                result_flags.push((flag, Some(next_arg.clone())));
-                            } else {
+                                result_flags.push((flag, Some(next_arg)));
+                            }
+                            else {
                                 result_flags.push((flag, None));
                             }
                         }
                     }
                 }
             }
+
             // If the string starts with *one* dash then it’s one or more
             // short arguments.
             else if bytes.starts_with(b"-") && arg != "-" {
-                let short_arg = OsStr::from_bytes(&bytes[1..]).unwrap();
+                let short_arg = OsStr::from_bytes(&bytes[1..]);
 
                 // If there’s an equals in it, then the argument immediately
                 // before the equals was the one that has the value, with the
@@ -226,9 +235,8 @@ impl Args {
                 // There’s no way to give two values in a cluster like this:
                 // it’s an error if any of the first set of arguments actually
                 // takes a value.
-                if let Some((before, after)) = split_on_equals(&short_arg) {
-                    let bytes = before.to_bytes();
-                    let (arg_with_value, other_args) = bytes.split_last().unwrap();
+                if let Some((before, after)) = split_on_equals(short_arg) {
+                    let (arg_with_value, other_args) = before.as_bytes().split_last().unwrap();
 
                     // Process the characters immediately following the dash...
                     for byte in other_args {
@@ -258,6 +266,7 @@ impl Args {
                         }
                     }
                 }
+
                 // If there’s no equals, then every character is parsed as
                 // its own short argument. However, if any of the arguments
                 // takes a value, then the *rest* of the string is used as
@@ -281,15 +290,14 @@ impl Args {
                             TakesValue::Necessary(values) |
                             TakesValue::Optional(values) => {
                                 if index < bytes.len() - 1 {
-                                    let remnants = &bytes[index + 1..];
-                                    result_flags.push((
-                                        flag,
-                                        Some(OsStringBytes::from_bytes(remnants).unwrap()),
-                                    ));
+                                    let remnants = &bytes[index+1 ..];
+                                    result_flags.push((flag, Some(OsStr::from_bytes(remnants))));
                                     break;
-                                } else if let Some(next_arg) = inputs.next() {
-                                    result_flags.push((flag, Some(next_arg.clone())));
-                                } else {
+                                }
+                                else if let Some(next_arg) = inputs.next() {
+                                    result_flags.push((flag, Some(next_arg)));
+                                }
+                                else {
                                     match arg.takes_value {
                                         TakesValue::Forbidden => {
                                             unreachable!()
@@ -307,19 +315,14 @@ impl Args {
                     }
                 }
             }
+
             // Otherwise, it’s a free string, usually a file name.
             else {
                 frees.push(arg)
             }
         }
 
-        Ok(Matches {
-            frees,
-            flags: MatchedFlags {
-                flags: result_flags,
-                strictness,
-            },
-        })
+        Ok(Matches { frees, flags: MatchedFlags { flags: result_flags, strictness } })
     }
 
     fn lookup_short(&self, short: ShortArg) -> Result<&Arg, ParseError> {
@@ -337,19 +340,22 @@ impl Args {
     }
 }
 
+
 /// The **matches** are the result of parsing the user’s command-line strings.
 #[derive(PartialEq, Debug)]
 pub struct Matches<'args> {
+
     /// The flags that were parsed from the user’s input.
-    pub flags: MatchedFlags<'args> ,
+    pub flags: MatchedFlags<'args>,
 
     /// All the strings that weren’t matched as arguments, as well as anything
-    /// after the special "--" string.
+    /// after the special “--” string.
     pub frees: Vec<&'args OsStr>,
 }
 
 #[derive(PartialEq, Debug)]
-pub struct MatchedFlags {
+pub struct MatchedFlags<'args> {
+
     /// The individual flags from the user’s input, in the order they were
     /// originally given.
     ///
@@ -362,7 +368,8 @@ pub struct MatchedFlags {
     strictness: Strictness,
 }
 
-impl MatchedFlags {
+impl<'a> MatchedFlags<'a> {
+
     /// Whether the given argument was specified.
     /// Returns `true` if it was, `false` if it wasn’t, and an error in
     /// strict mode if it was specified more than once.
@@ -442,8 +449,7 @@ impl MatchedFlags {
     /// Counts the number of occurrences of the given argument, even in
     /// strict mode.
     pub fn count(&self, arg: &Arg) -> usize {
-        self.flags
-            .iter()
+        self.flags.iter()
             .filter(|tuple| tuple.0.matches(arg))
             .count()
     }
@@ -455,10 +461,12 @@ impl MatchedFlags {
     }
 }
 
+
 /// A problem with the user’s input that meant it couldn’t be parsed into a
 /// coherent list of arguments.
 #[derive(PartialEq, Debug)]
 pub enum ParseError {
+
     /// A flag that has to take a value was not given one.
     NeedsValue { flag: Flag, values: Option<Values> },
 
@@ -487,12 +495,14 @@ impl fmt::Display for ParseError {
     }
 }
 
+
 /// Splits a string on its `=` character, returning the two substrings on
 /// either side. Returns `None` if there’s no equals or a string is missing.
-fn split_on_equals<'a>(input: &'a Cow<OsStr>) -> Option<(OsString, OsString)> {
-    if let Some(index) = input.to_bytes().iter().position(|elem| *elem == b'=') {
-        let bytes = input.to_bytes();
-        let (before, after) = bytes.split_at(index);
+fn split_on_equals(input: &OsStr) -> Option<(&OsStr, &OsStr)> {
+    use std::os::unix::ffi::OsStrExt;
+
+    if let Some(index) = input.as_bytes().iter().position(|elem| *elem == b'=') {
+        let (before, after) = input.as_bytes().split_at(index);
 
         // The after string contains the = that we need to remove.
         if ! before.is_empty() && after.len() >= 2 {
@@ -540,6 +550,7 @@ mod split_test {
     test_split!(more: "this=that=other" => "this",   "that=other");
 }
 
+
 #[cfg(test)]
 mod parse_test {
     use super::*;
@@ -580,31 +591,16 @@ mod parse_test {
         };
     }
 
-    const SUGGESTIONS: Values = &["example"];
+    const SUGGESTIONS: Values = &[ "example" ];
 
     static TEST_ARGS: &[&Arg] = &[
-        &Arg {
-            short: Some(b'l'),
-            long: "long",
-            takes_value: TakesValue::Forbidden,
-        },
-        &Arg {
-            short: Some(b'v'),
-            long: "verbose",
-            takes_value: TakesValue::Forbidden,
-        },
-        &Arg {
-            short: Some(b'c'),
-            long: "count",
-            takes_value: TakesValue::Necessary(None),
-        },
-        &Arg {
-            short: Some(b't'),
-            long: "type",
-            takes_value: TakesValue::Necessary(Some(SUGGESTIONS)),
-        },
+        &Arg { short: Some(b'l'), long: "long",     takes_value: TakesValue::Forbidden },
+        &Arg { short: Some(b'v'), long: "verbose",  takes_value: TakesValue::Forbidden },
+        &Arg { short: Some(b'c'), long: "count",    takes_value: TakesValue::Necessary(None) },
+        &Arg { short: Some(b't'), long: "type",     takes_value: TakesValue::Necessary(Some(SUGGESTIONS)) }
     ];
 
+
     // Just filenames
     test!(empty:       []       => frees: [],         flags: []);
     test!(one_arg:     ["exa"]  => frees: [ "exa" ],  flags: []);
@@ -616,6 +612,7 @@ mod parse_test {
     test!(two_arg_l:   ["--", "--long"]  => frees: [ "--long" ],  flags: []);
     test!(two_arg_s:   ["--", "-l"]      => frees: [ "-l" ],      flags: []);
 
+
     // Long args
     test!(long:        ["--long"]               => frees: [],       flags: [ (Flag::Long("long"), None) ]);
     test!(long_then:   ["--long", "4"]          => frees: [ "4" ],  flags: [ (Flag::Long("long"), None) ]);
@@ -624,13 +621,14 @@ mod parse_test {
     // Long args with values
     test!(bad_equals:  ["--long=equals"]  => error ForbiddenValue { flag: Flag::Long("long") });
     test!(no_arg:      ["--count"]        => error NeedsValue     { flag: Flag::Long("count"), values: None });
-    test!(arg_equals:  ["--count=4"]      => frees: [],  flags: [ (Flag::Long("count"), Some(OsString::from("4"))) ]);
-    test!(arg_then:    ["--count", "4"]   => frees: [],  flags: [ (Flag::Long("count"), Some(OsString::from("4"))) ]);
+    test!(arg_equals:  ["--count=4"]      => frees: [],  flags: [ (Flag::Long("count"), Some(OsStr::new("4"))) ]);
+    test!(arg_then:    ["--count", "4"]   => frees: [],  flags: [ (Flag::Long("count"), Some(OsStr::new("4"))) ]);
 
     // Long args with values and suggestions
     test!(no_arg_s:      ["--type"]         => error NeedsValue { flag: Flag::Long("type"), values: Some(SUGGESTIONS) });
-    test!(arg_equals_s:  ["--type=exa"]     => frees: [],  flags: [ (Flag::Long("type"), Some(OsString::from("exa"))) ]);
-    test!(arg_then_s:    ["--type", "exa"]  => frees: [],  flags: [ (Flag::Long("type"), Some(OsString::from("exa"))) ]);
+    test!(arg_equals_s:  ["--type=exa"]     => frees: [],  flags: [ (Flag::Long("type"), Some(OsStr::new("exa"))) ]);
+    test!(arg_then_s:    ["--type", "exa"]  => frees: [],  flags: [ (Flag::Long("type"), Some(OsStr::new("exa"))) ]);
+
 
     // Short args
     test!(short:       ["-l"]            => frees: [],       flags: [ (Flag::Short(b'l'), None) ]);
@@ -641,17 +639,18 @@ mod parse_test {
     // Short args with values
     test!(bad_short:          ["-l=equals"]   => error ForbiddenValue { flag: Flag::Short(b'l') });
     test!(short_none:         ["-c"]          => error NeedsValue     { flag: Flag::Short(b'c'), values: None });
-    test!(short_arg_eq:       ["-c=4"]        => frees: [],  flags: [(Flag::Short(b'c'), Some(OsString::from("4"))) ]);
-    test!(short_arg_then:     ["-c", "4"]     => frees: [],  flags: [(Flag::Short(b'c'), Some(OsString::from("4"))) ]);
-    test!(short_two_together: ["-lctwo"]      => frees: [],  flags: [(Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(OsString::from("two"))) ]);
-    test!(short_two_equals:   ["-lc=two"]     => frees: [],  flags: [(Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(OsString::from("two"))) ]);
-    test!(short_two_next:     ["-lc", "two"]  => frees: [],  flags: [(Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(OsString::from("two"))) ]);
+    test!(short_arg_eq:       ["-c=4"]        => frees: [],  flags: [(Flag::Short(b'c'), Some(OsStr::new("4"))) ]);
+    test!(short_arg_then:     ["-c", "4"]     => frees: [],  flags: [(Flag::Short(b'c'), Some(OsStr::new("4"))) ]);
+    test!(short_two_together: ["-lctwo"]      => frees: [],  flags: [(Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(OsStr::new("two"))) ]);
+    test!(short_two_equals:   ["-lc=two"]     => frees: [],  flags: [(Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(OsStr::new("two"))) ]);
+    test!(short_two_next:     ["-lc", "two"]  => frees: [],  flags: [(Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(OsStr::new("two"))) ]);
 
     // Short args with values and suggestions
     test!(short_none_s:         ["-t"]         => error NeedsValue { flag: Flag::Short(b't'), values: Some(SUGGESTIONS) });
-    test!(short_two_together_s: ["-texa"]      => frees: [],  flags: [(Flag::Short(b't'), Some(OsString::from("exa"))) ]);
-    test!(short_two_equals_s:   ["-t=exa"]     => frees: [],  flags: [(Flag::Short(b't'), Some(OsString::from("exa"))) ]);
-    test!(short_two_next_s:     ["-t", "exa"]  => frees: [],  flags: [(Flag::Short(b't'), Some(OsString::from("exa"))) ]);
+    test!(short_two_together_s: ["-texa"]      => frees: [],  flags: [(Flag::Short(b't'), Some(OsStr::new("exa"))) ]);
+    test!(short_two_equals_s:   ["-t=exa"]     => frees: [],  flags: [(Flag::Short(b't'), Some(OsStr::new("exa"))) ]);
+    test!(short_two_next_s:     ["-t", "exa"]  => frees: [],  flags: [(Flag::Short(b't'), Some(OsStr::new("exa"))) ]);
+
 
     // Unknown args
     test!(unknown_long:          ["--quiet"]      => error UnknownArgument      { attempt: OsString::from("quiet") });
@@ -662,6 +661,7 @@ mod parse_test {
     test!(unknown_short_2nd_eq:  ["-lq=shhh"]     => error UnknownShortArgument { attempt: b'q' });
 }
 
+
 #[cfg(test)]
 mod matches_test {
     use super::*;
@@ -680,16 +680,9 @@ mod matches_test {
         };
     }
 
-    static VERBOSE: Arg = Arg {
-        short: Some(b'v'),
-        long: "verbose",
-        takes_value: TakesValue::Forbidden,
-    };
-    static COUNT: Arg = Arg {
-        short: Some(b'c'),
-        long: "count",
-        takes_value: TakesValue::Necessary(None),
-    };
+    static VERBOSE: Arg = Arg { short: Some(b'v'), long: "verbose", takes_value: TakesValue::Forbidden };
+    static COUNT:   Arg = Arg { short: Some(b'c'), long: "count",   takes_value: TakesValue::Necessary(None) };
+
 
     test!(short_never:  [],                                                              has VERBOSE => false);
     test!(short_once:   [(Flag::Short(b'v'), None)],                                     has VERBOSE => true);
@@ -698,16 +691,17 @@ mod matches_test {
     test!(long_twice:   [(Flag::Long("verbose"), None), (Flag::Long("verbose"), None)],  has VERBOSE => true);
     test!(long_mixed:   [(Flag::Long("verbose"), None), (Flag::Short(b'v'), None)],      has VERBOSE => true);
 
+
     #[test]
     fn only_count() {
         let everything = OsString::from("everything");
 
         let flags = MatchedFlags {
-            flags: vec![(Flag::Short(b'c'), Some(everything.clone()))],
+            flags: vec![ (Flag::Short(b'c'), Some(&*everything)) ],
             strictness: Strictness::UseLastArguments,
         };
 
-        assert_eq!(flags.get(&COUNT), Ok(Some(everything)));
+        assert_eq!(flags.get(&COUNT), Ok(Some(&*everything)));
     }
 
     #[test]
@@ -716,23 +710,18 @@ mod matches_test {
         let nothing    = OsString::from("nothing");
 
         let flags = MatchedFlags {
-            flags: vec![
-                (Flag::Short(b'c'), Some(everything)),
-                (Flag::Short(b'c'), Some(nothing.clone())),
-            ],
+            flags: vec![ (Flag::Short(b'c'), Some(&*everything)),
+                         (Flag::Short(b'c'), Some(&*nothing)) ],
             strictness: Strictness::UseLastArguments,
         };
 
-        assert_eq!(flags.get(&COUNT), Ok(Some(nothing)));
+        assert_eq!(flags.get(&COUNT), Ok(Some(&*nothing)));
     }
 
     #[test]
     fn no_count() {
-        let flags = MatchedFlags {
-            flags: Vec::new(),
-            strictness: Strictness::UseLastArguments,
-        };
+        let flags = MatchedFlags { flags: Vec::new(), strictness: Strictness::UseLastArguments };
 
         assert_eq!(flags.has(&COUNT).unwrap(), false);
     }
-}
+}

+ 14 - 2
src/output/table.rs

@@ -49,6 +49,7 @@ pub struct Columns {
 }
 
 impl Columns {
+
     pub fn collect(&self, actually_enable_git: bool) -> Vec<Column> {
         let mut columns = Vec::with_capacity(4);
 
@@ -118,6 +119,7 @@ impl Columns {
     }
 }
 
+
 /// A table contains these.
 #[derive(Debug, Copy, Clone)]
 pub enum Column {
@@ -149,6 +151,7 @@ pub enum Alignment {
 }
 
 impl Column {
+
     /// Get the alignment this column should use.
     #[cfg(unix)]
     pub fn alignment(self) -> Alignment {
@@ -195,9 +198,11 @@ impl Column {
     }
 }
 
+
 /// 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,
@@ -216,6 +221,7 @@ impl Default for SizeFormat {
     }
 }
 
+
 /// The types of a file’s time fields. These three fields are standard
 /// across most (all?) operating systems.
 #[derive(PartialEq, Debug, Copy, Clone)]
@@ -235,6 +241,7 @@ pub enum TimeType {
 }
 
 impl TimeType {
+
     /// Returns the text to use for a column’s heading in the columns output.
     pub fn header(self) -> &'static str {
         match self {
@@ -255,12 +262,13 @@ impl TimeType {
 #[allow(clippy::struct_excessive_bools)]
 pub struct TimeTypes {
     pub modified: bool,
-    pub changed: bool,
+    pub changed:  bool,
     pub accessed: bool,
-    pub created: 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() -> Self {
@@ -273,11 +281,13 @@ impl Default for TimeTypes {
     }
 }
 
+
 /// The **environment** struct contains any data that could change between
 /// running instances of exa, depending on the user’s computer’s configuration.
 ///
 /// Any environment field should be able to be mocked up for test runs.
 pub struct Environment {
+
     /// Localisation rules for formatting numbers.
     numeric: locale::Numeric,
 
@@ -330,6 +340,7 @@ lazy_static! {
     static ref ENVIRONMENT: Environment = Environment::load_all();
 }
 
+
 pub struct Table<'a> {
     columns: Vec<Column>,
     theme: &'a Theme,
@@ -488,6 +499,7 @@ impl<'a, 'f> Table<'a> {
     }
 }
 
+
 pub struct TableWidths(Vec<usize>);
 
 impl Deref for TableWidths {