Преглед изворни кода

Merge pull request #405 from gierens/rustfmt

Enable Rustfmt
Christina Sørensen пре 2 година
родитељ
комит
0e06409b07
61 измењених фајлова са 2331 додато и 1775 уклоњено
  1. 5 2
      .github/workflows/unit-tests.yml
  2. 0 1
      .rustfmt.toml
  3. 5 1
      benches/my_benchmark.rs
  4. 36 24
      build.rs
  5. 27 34
      src/fs/dir.rs
  6. 7 12
      src/fs/dir_action.rs
  7. 89 61
      src/fs/feature/git.rs
  8. 4 4
      src/fs/feature/mod.rs
  9. 70 84
      src/fs/feature/xattr.rs
  10. 14 27
      src/fs/fields.rs
  11. 153 125
      src/fs/file.rs
  12. 31 40
      src/fs/filter.rs
  13. 11 11
      src/fs/mounts/linux.rs
  14. 10 6
      src/fs/mounts/macos.rs
  15. 5 5
      src/fs/mounts/mod.rs
  16. 13 9
      src/info/filetype.rs
  17. 2 5
      src/info/sources.rs
  18. 19 14
      src/logger.rs
  19. 124 48
      src/main.rs
  20. 31 29
      src/options/dir_action.rs
  21. 12 13
      src/options/error.rs
  22. 27 16
      src/options/file_name.rs
  23. 59 84
      src/options/filter.rs
  24. 0 1
      src/options/flags.rs
  25. 6 11
      src/options/help.rs
  26. 42 22
      src/options/mod.rs
  27. 136 117
      src/options/parser.rs
  28. 53 42
      src/options/theme.rs
  29. 1 4
      src/options/vars.rs
  30. 8 8
      src/options/version.rs
  31. 176 128
      src/options/view.rs
  32. 9 15
      src/output/cell.rs
  33. 116 62
      src/output/details.rs
  34. 0 1
      src/output/escape.rs
  35. 60 59
      src/output/file_name.rs
  36. 12 11
      src/output/grid.rs
  37. 86 48
      src/output/grid_details.rs
  38. 6 3
      src/output/icons.rs
  39. 1 2
      src/output/lines.rs
  40. 4 7
      src/output/mod.rs
  41. 60 38
      src/output/render/blocks.rs
  42. 3 4
      src/output/render/filetype.rs
  43. 43 37
      src/output/render/git.rs
  44. 52 23
      src/output/render/groups.rs
  45. 1 4
      src/output/render/inode.rs
  46. 31 19
      src/output/render/links.rs
  47. 107 36
      src/output/render/octal.rs
  48. 141 78
      src/output/render/permissions.rs
  49. 6 8
      src/output/render/securityctx.rs
  50. 70 39
      src/output/render/size.rs
  51. 4 2
      src/output/render/times.rs
  52. 34 11
      src/output/render/users.rs
  53. 88 109
      src/output/table.rs
  54. 30 29
      src/output/time.rs
  55. 27 21
      src/output/tree.rs
  56. 36 31
      src/theme/default_theme.rs
  57. 37 24
      src/theme/lsc.rs
  58. 67 48
      src/theme/mod.rs
  59. 18 9
      src/theme/ui_styles.rs
  60. 5 9
      tests/cli_tests.rs
  61. 1 0
      treefmt.nix

+ 5 - 2
.github/workflows/unit-tests.yml

@@ -48,8 +48,11 @@ jobs:
           max_attempts: 5
           max_attempts: 5
           command: cargo install cargo-hack
           command: cargo install cargo-hack
 
 
-      - name: Run unit tests
-        run: cargo hack test 
+      - name: Run rustfmt checks
+        run: cargo fmt --check
 
 
       - name: Run clippy lints
       - name: Run clippy lints
         run: cargo clippy -- -D warnings 
         run: cargo clippy -- -D warnings 
+
+      - name: Run unit tests
+        run: cargo hack test 

+ 0 - 1
.rustfmt.toml

@@ -1 +0,0 @@
-disable_all_formatting = true

+ 5 - 1
benches/my_benchmark.rs

@@ -1,7 +1,11 @@
 use criterion::{black_box, criterion_group, criterion_main, Criterion};
 use criterion::{black_box, criterion_group, criterion_main, Criterion};
 
 
 pub fn criterion_benchmark(c: &mut Criterion) {
 pub fn criterion_benchmark(c: &mut Criterion) {
-    c.bench_function("logger", |b| b.iter(|| eza::logger::configure(black_box(std::env::var_os(eza::options::vars::EZA_DEBUG)))));
+    c.bench_function("logger", |b| {
+        b.iter(|| {
+            eza::logger::configure(black_box(std::env::var_os(eza::options::vars::EZA_DEBUG)))
+        })
+    });
 }
 }
 
 
 criterion_group!(benches, criterion_benchmark);
 criterion_group!(benches, criterion_benchmark);

+ 36 - 24
build.rs

@@ -9,7 +9,6 @@
 ///
 ///
 /// - https://stackoverflow.com/q/43753491/3484614
 /// - https://stackoverflow.com/q/43753491/3484614
 /// - https://crates.io/crates/vergen
 /// - https://crates.io/crates/vergen
-
 use std::env;
 use std::env;
 use std::fs::File;
 use std::fs::File;
 use std::io::{self, Write};
 use std::io::{self, Write};
@@ -17,31 +16,40 @@ use std::path::PathBuf;
 
 
 use chrono::prelude::*;
 use chrono::prelude::*;
 
 
-
 /// The build script entry point.
 /// The build script entry point.
 fn main() -> io::Result<()> {
 fn main() -> io::Result<()> {
     #![allow(clippy::write_with_newline)]
     #![allow(clippy::write_with_newline)]
 
 
     let tagline = "eza - A modern, maintained replacement for ls";
     let tagline = "eza - A modern, maintained replacement for ls";
-    let url     = "https://github.com/eza-community/eza";
-
-    let ver =
-        if is_debug_build() {
-            format!("{}\nv{} \\1;31m(pre-release debug build!)\\0m\n\\1;4;34m{}\\0m", tagline, version_string(), url)
-        }
-        else if is_development_version() {
-            format!("{}\nv{} [{}] built on {} \\1;31m(pre-release!)\\0m\n\\1;4;34m{}\\0m", tagline, version_string(), git_hash(), build_date(), url)
-        }
-        else {
-            format!("{}\nv{}\n\\1;4;34m{}\\0m", tagline, version_string(), url)
-        };
+    let url = "https://github.com/eza-community/eza";
+
+    let ver = if is_debug_build() {
+        format!(
+            "{}\nv{} \\1;31m(pre-release debug build!)\\0m\n\\1;4;34m{}\\0m",
+            tagline,
+            version_string(),
+            url
+        )
+    } else if is_development_version() {
+        format!(
+            "{}\nv{} [{}] built on {} \\1;31m(pre-release!)\\0m\n\\1;4;34m{}\\0m",
+            tagline,
+            version_string(),
+            git_hash(),
+            build_date(),
+            url
+        )
+    } else {
+        format!("{}\nv{}\n\\1;4;34m{}\\0m", tagline, version_string(), url)
+    };
 
 
     // We need to create these files in the Cargo output directory.
     // We need to create these files in the Cargo output directory.
     let out = PathBuf::from(env::var("OUT_DIR").unwrap());
     let out = PathBuf::from(env::var("OUT_DIR").unwrap());
     let path = &out.join("version_string.txt");
     let path = &out.join("version_string.txt");
 
 
     // Bland version text
     // Bland version text
-    let mut f = File::create(path).unwrap_or_else(|_| { panic!("{}", path.to_string_lossy().to_string()) });
+    let mut f =
+        File::create(path).unwrap_or_else(|_| panic!("{}", path.to_string_lossy().to_string()));
     writeln!(f, "{}", strip_codes(&ver))?;
     writeln!(f, "{}", strip_codes(&ver))?;
 
 
     Ok(())
     Ok(())
@@ -49,9 +57,10 @@ fn main() -> io::Result<()> {
 
 
 /// Removes escape codes from a string.
 /// Removes escape codes from a string.
 fn strip_codes(input: &str) -> String {
 fn strip_codes(input: &str) -> String {
-    input.replace("\\0m", "")
-         .replace("\\1;31m", "")
-         .replace("\\1;4;34m", "")
+    input
+        .replace("\\0m", "")
+        .replace("\\1;31m", "")
+        .replace("\\1;4;34m", "")
 }
 }
 
 
 /// Retrieve the project’s current Git hash, as a string.
 /// Retrieve the project’s current Git hash, as a string.
@@ -61,8 +70,12 @@ fn git_hash() -> String {
     String::from_utf8_lossy(
     String::from_utf8_lossy(
         &Command::new("git")
         &Command::new("git")
             .args(["rev-parse", "--short", "HEAD"])
             .args(["rev-parse", "--short", "HEAD"])
-            .output().unwrap()
-            .stdout).trim().to_string()
+            .output()
+            .unwrap()
+            .stdout,
+    )
+    .trim()
+    .to_string()
 }
 }
 
 
 /// Whether we should show pre-release info in the version string.
 /// Whether we should show pre-release info in the version string.
@@ -88,7 +101,7 @@ fn version_string() -> String {
     let mut ver = cargo_version();
     let mut ver = cargo_version();
 
 
     let feats = nonstandard_features_string();
     let feats = nonstandard_features_string();
-    if ! feats.is_empty() {
+    if !feats.is_empty() {
         ver.push_str(&format!(" [{}]", &feats));
         ver.push_str(&format!(" [{}]", &feats));
     }
     }
 
 
@@ -98,7 +111,7 @@ fn version_string() -> String {
 /// Finds whether a feature is enabled by examining the Cargo variable.
 /// Finds whether a feature is enabled by examining the Cargo variable.
 fn feature_enabled(name: &str) -> bool {
 fn feature_enabled(name: &str) -> bool {
     env::var(format!("CARGO_FEATURE_{}", name))
     env::var(format!("CARGO_FEATURE_{}", name))
-        .map(|e| ! e.is_empty())
+        .map(|e| !e.is_empty())
         .unwrap_or(false)
         .unwrap_or(false)
 }
 }
 
 
@@ -108,8 +121,7 @@ fn nonstandard_features_string() -> String {
 
 
     if feature_enabled("GIT") {
     if feature_enabled("GIT") {
         s.push("+git");
         s.push("+git");
-    }
-    else {
+    } else {
         s.push("-git");
         s.push("-git");
     }
     }
 
 

+ 27 - 34
src/fs/dir.rs

@@ -1,7 +1,7 @@
 use crate::fs::feature::git::GitCache;
 use crate::fs::feature::git::GitCache;
 use crate::fs::fields::GitStatus;
 use crate::fs::fields::GitStatus;
-use std::io;
 use std::fs;
 use std::fs;
+use std::io;
 use std::path::{Path, PathBuf};
 use std::path::{Path, PathBuf};
 use std::slice::Iter as SliceIter;
 use std::slice::Iter as SliceIter;
 
 
@@ -9,7 +9,6 @@ use log::*;
 
 
 use crate::fs::File;
 use crate::fs::File;
 
 
-
 /// A **Dir** provides a cached list of the file paths in a directory that’s
 /// A **Dir** provides a cached list of the file paths in a directory that’s
 /// being listed.
 /// being listed.
 ///
 ///
@@ -17,7 +16,6 @@ use crate::fs::File;
 /// check the existence of surrounding files, then highlight themselves
 /// check the existence of surrounding files, then highlight themselves
 /// accordingly. (See `File#get_source_files`)
 /// accordingly. (See `File#get_source_files`)
 pub struct Dir {
 pub struct Dir {
-
     /// A vector of the files that have been read from this directory.
     /// A vector of the files that have been read from this directory.
     contents: Vec<PathBuf>,
     contents: Vec<PathBuf>,
 
 
@@ -26,7 +24,6 @@ pub struct Dir {
 }
 }
 
 
 impl Dir {
 impl Dir {
-
     /// Create a new Dir object filled with all the files in the directory
     /// Create a new Dir object filled with all the files in the directory
     /// pointed to by the given path. Fails if the directory can’t be read, or
     /// pointed to by the given path. Fails if the directory can’t be read, or
     /// isn’t actually a directory, or if there’s an IO error that occurs at
     /// isn’t actually a directory, or if there’s an IO error that occurs at
@@ -39,8 +36,8 @@ impl Dir {
         info!("Reading directory {:?}", &path);
         info!("Reading directory {:?}", &path);
 
 
         let contents = fs::read_dir(&path)?
         let contents = fs::read_dir(&path)?
-                          .map(|result| result.map(|entry| entry.path()))
-                          .collect::<Result<_, _>>()?;
+            .map(|result| result.map(|entry| entry.path()))
+            .collect::<Result<_, _>>()?;
 
 
         info!("Read directory success {:?}", &path);
         info!("Read directory success {:?}", &path);
         Ok(Self { contents, path })
         Ok(Self { contents, path })
@@ -48,12 +45,18 @@ impl Dir {
 
 
     /// Produce an iterator of IO results of trying to read all the files in
     /// Produce an iterator of IO results of trying to read all the files in
     /// this directory.
     /// this directory.
-    pub fn files<'dir, 'ig>(&'dir self, dots: DotFilter, git: Option<&'ig GitCache>, git_ignoring: bool, deref_links: bool) -> Files<'dir, 'ig> {
+    pub fn files<'dir, 'ig>(
+        &'dir self,
+        dots: DotFilter,
+        git: Option<&'ig GitCache>,
+        git_ignoring: bool,
+        deref_links: bool,
+    ) -> Files<'dir, 'ig> {
         Files {
         Files {
-            inner:     self.contents.iter(),
-            dir:       self,
-            dotfiles:  dots.shows_dotfiles(),
-            dots:      dots.dots(),
+            inner: self.contents.iter(),
+            dir: self,
+            dotfiles: dots.shows_dotfiles(),
+            dots: dots.dots(),
             git,
             git,
             git_ignoring,
             git_ignoring,
             deref_links,
             deref_links,
@@ -71,10 +74,8 @@ impl Dir {
     }
     }
 }
 }
 
 
-
 /// Iterator over reading the contents of a directory as `File` objects.
 /// Iterator over reading the contents of a directory as `File` objects.
 pub struct Files<'dir, 'ig> {
 pub struct Files<'dir, 'ig> {
-
     /// The internal iterator over the paths that have been read already.
     /// The internal iterator over the paths that have been read already.
     inner: SliceIter<'dir, PathBuf>,
     inner: SliceIter<'dir, PathBuf>,
 
 
@@ -112,26 +113,26 @@ impl<'dir, 'ig> Files<'dir, 'ig> {
         loop {
         loop {
             if let Some(path) = self.inner.next() {
             if let Some(path) = self.inner.next() {
                 let filename = File::filename(path);
                 let filename = File::filename(path);
-                if ! self.dotfiles && filename.starts_with('.') {
+                if !self.dotfiles && filename.starts_with('.') {
                     continue;
                     continue;
                 }
                 }
 
 
                 // Also hide _prefix files on Windows because it's used by old applications
                 // Also hide _prefix files on Windows because it's used by old applications
                 // as an alternative to dot-prefix files.
                 // as an alternative to dot-prefix files.
                 #[cfg(windows)]
                 #[cfg(windows)]
-                if ! self.dotfiles && filename.starts_with('_') {
+                if !self.dotfiles && filename.starts_with('_') {
                     continue;
                     continue;
                 }
                 }
 
 
                 if self.git_ignoring {
                 if self.git_ignoring {
                     let git_status = self.git.map(|g| g.get(path, false)).unwrap_or_default();
                     let git_status = self.git.map(|g| g.get(path, false)).unwrap_or_default();
                     if git_status.unstaged == GitStatus::Ignored {
                     if git_status.unstaged == GitStatus::Ignored {
-                         continue;
+                        continue;
                     }
                     }
                 }
                 }
 
 
                 let file = File::from_args(path.clone(), self.dir, filename, self.deref_links)
                 let file = File::from_args(path.clone(), self.dir, filename, self.deref_links)
-                                 .map_err(|e| (path.clone(), e));
+                    .map_err(|e| (path.clone(), e));
 
 
                 // Windows has its own concept of hidden files, when dotfiles are
                 // Windows has its own concept of hidden files, when dotfiles are
                 // hidden Windows hidden files should also be filtered out
                 // hidden Windows hidden files should also be filtered out
@@ -143,7 +144,7 @@ impl<'dir, 'ig> Files<'dir, 'ig> {
                 return Some(file);
                 return Some(file);
             }
             }
 
 
-            return None
+            return None;
         }
         }
     }
     }
 }
 }
@@ -151,7 +152,6 @@ impl<'dir, 'ig> Files<'dir, 'ig> {
 /// The dot directories that need to be listed before actual files, if any.
 /// The dot directories that need to be listed before actual files, if any.
 /// If these aren’t being printed, then `FilesNext` is used to skip them.
 /// If these aren’t being printed, then `FilesNext` is used to skip them.
 enum DotsNext {
 enum DotsNext {
-
     /// List the `.` directory next.
     /// List the `.` directory next.
     Dot,
     Dot,
 
 
@@ -169,30 +169,24 @@ impl<'dir, 'ig> Iterator for Files<'dir, 'ig> {
         match self.dots {
         match self.dots {
             DotsNext::Dot => {
             DotsNext::Dot => {
                 self.dots = DotsNext::DotDot;
                 self.dots = DotsNext::DotDot;
-                Some(File::new_aa_current(self.dir)
-                          .map_err(|e| (Path::new(".").to_path_buf(), e)))
+                Some(File::new_aa_current(self.dir).map_err(|e| (Path::new(".").to_path_buf(), e)))
             }
             }
 
 
             DotsNext::DotDot => {
             DotsNext::DotDot => {
                 self.dots = DotsNext::Files;
                 self.dots = DotsNext::Files;
-                Some(File::new_aa_parent(self.parent(), self.dir)
-                          .map_err(|e| (self.parent(), e)))
+                Some(File::new_aa_parent(self.parent(), self.dir).map_err(|e| (self.parent(), e)))
             }
             }
 
 
-            DotsNext::Files => {
-                self.next_visible_file()
-            }
+            DotsNext::Files => self.next_visible_file(),
         }
         }
     }
     }
 }
 }
 
 
-
 /// Usually files in Unix use a leading dot to be hidden or visible, but two
 /// Usually files in Unix use a leading dot to be hidden or visible, but two
 /// entries in particular are “extra-hidden”: `.` and `..`, which only become
 /// entries in particular are “extra-hidden”: `.` and `..`, which only become
 /// visible after an extra `-a` option.
 /// visible after an extra `-a` option.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum DotFilter {
 pub enum DotFilter {
-
     /// Shows files, dotfiles, and `.` and `..`.
     /// Shows files, dotfiles, and `.` and `..`.
     DotfilesAndDots,
     DotfilesAndDots,
 
 
@@ -210,12 +204,11 @@ impl Default for DotFilter {
 }
 }
 
 
 impl DotFilter {
 impl DotFilter {
-
     /// Whether this filter should show dotfiles in a listing.
     /// Whether this filter should show dotfiles in a listing.
     fn shows_dotfiles(self) -> bool {
     fn shows_dotfiles(self) -> bool {
         match self {
         match self {
-            Self::JustFiles       => false,
-            Self::Dotfiles        => true,
+            Self::JustFiles => false,
+            Self::Dotfiles => true,
             Self::DotfilesAndDots => true,
             Self::DotfilesAndDots => true,
         }
         }
     }
     }
@@ -223,9 +216,9 @@ impl DotFilter {
     /// Whether this filter should add dot directories to a listing.
     /// Whether this filter should add dot directories to a listing.
     fn dots(self) -> DotsNext {
     fn dots(self) -> DotsNext {
         match self {
         match self {
-            Self::JustFiles        => DotsNext::Files,
-            Self::Dotfiles         => DotsNext::Files,
-            Self::DotfilesAndDots  => DotsNext::Dot,
+            Self::JustFiles => DotsNext::Files,
+            Self::Dotfiles => DotsNext::Files,
+            Self::DotfilesAndDots => DotsNext::Dot,
         }
         }
     }
     }
 }
 }

+ 7 - 12
src/fs/dir_action.rs

@@ -21,7 +21,6 @@
 /// directories inline, with their contents immediately underneath.
 /// directories inline, with their contents immediately underneath.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum DirAction {
 pub enum DirAction {
-
     /// This directory should be listed along with the regular files, instead
     /// This directory should be listed along with the regular files, instead
     /// of having its contents queried.
     /// of having its contents queried.
     AsFile,
     AsFile,
@@ -37,30 +36,27 @@ pub enum DirAction {
 }
 }
 
 
 impl DirAction {
 impl DirAction {
-
     /// Gets the recurse options, if this dir action has any.
     /// Gets the recurse options, if this dir action has any.
     pub fn recurse_options(self) -> Option<RecurseOptions> {
     pub fn recurse_options(self) -> Option<RecurseOptions> {
         match self {
         match self {
-            Self::Recurse(o)  => Some(o),
-            _                 => None,
+            Self::Recurse(o) => Some(o),
+            _ => None,
         }
         }
     }
     }
 
 
     /// Whether to treat directories as regular files or not.
     /// Whether to treat directories as regular files or not.
     pub fn treat_dirs_as_files(self) -> bool {
     pub fn treat_dirs_as_files(self) -> bool {
         match self {
         match self {
-            Self::AsFile      => true,
-            Self::Recurse(o)  => o.tree,
-            Self::List        => false,
+            Self::AsFile => true,
+            Self::Recurse(o) => o.tree,
+            Self::List => false,
         }
         }
     }
     }
 }
 }
 
 
-
 /// The options that determine how to recurse into a directory.
 /// The options that determine how to recurse into a directory.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub struct RecurseOptions {
 pub struct RecurseOptions {
-
     /// Whether recursion should be done as a tree or as multiple individual
     /// Whether recursion should be done as a tree or as multiple individual
     /// views of files.
     /// views of files.
     pub tree: bool,
     pub tree: bool,
@@ -71,12 +67,11 @@ pub struct RecurseOptions {
 }
 }
 
 
 impl RecurseOptions {
 impl RecurseOptions {
-
     /// Returns whether a directory of the given depth would be too deep.
     /// Returns whether a directory of the given depth would be too deep.
     pub fn is_too_deep(self, depth: usize) -> bool {
     pub fn is_too_deep(self, depth: usize) -> bool {
         match self.max_depth {
         match self.max_depth {
-            None     => false,
-            Some(d)  => d <= depth
+            None => false,
+            Some(d) => d <= depth,
         }
         }
     }
     }
 }
 }

+ 89 - 61
src/fs/feature/git.rs

@@ -11,13 +11,11 @@ use log::*;
 
 
 use crate::fs::fields as f;
 use crate::fs::fields as f;
 
 
-
 /// A **Git cache** is assembled based on the user’s input arguments.
 /// A **Git cache** is assembled based on the user’s input arguments.
 ///
 ///
 /// This uses vectors to avoid the overhead of hashing: it’s not worth it when the
 /// This uses vectors to avoid the overhead of hashing: it’s not worth it when the
 /// expected number of Git repositories per exa invocation is 0 or 1...
 /// expected number of Git repositories per exa invocation is 0 or 1...
 pub struct GitCache {
 pub struct GitCache {
-
     /// A list of discovered Git repositories and their paths.
     /// A list of discovered Git repositories and their paths.
     repos: Vec<GitRepo>,
     repos: Vec<GitRepo>,
 
 
@@ -31,7 +29,8 @@ impl GitCache {
     }
     }
 
 
     pub fn get(&self, index: &Path, prefix_lookup: bool) -> f::Git {
     pub fn get(&self, index: &Path, prefix_lookup: bool) -> f::Git {
-        self.repos.iter()
+        self.repos
+            .iter()
             .find(|repo| repo.has_path(index))
             .find(|repo| repo.has_path(index))
             .map(|repo| repo.search(index, prefix_lookup))
             .map(|repo| repo.search(index, prefix_lookup))
             .unwrap_or_default()
             .unwrap_or_default()
@@ -41,7 +40,8 @@ impl GitCache {
 use std::iter::FromIterator;
 use std::iter::FromIterator;
 impl FromIterator<PathBuf> for GitCache {
 impl FromIterator<PathBuf> for GitCache {
     fn from_iter<I>(iter: I) -> Self
     fn from_iter<I>(iter: I) -> Self
-    where I: IntoIterator<Item=PathBuf>
+    where
+        I: IntoIterator<Item = PathBuf>,
     {
     {
         let iter = iter.into_iter();
         let iter = iter.into_iter();
         let mut git = Self {
         let mut git = Self {
@@ -66,16 +66,17 @@ impl FromIterator<PathBuf> for GitCache {
         for path in iter {
         for path in iter {
             if git.misses.contains(&path) {
             if git.misses.contains(&path) {
                 debug!("Skipping {:?} because it already came back Gitless", path);
                 debug!("Skipping {:?} because it already came back Gitless", path);
-            }
-            else if git.repos.iter().any(|e| e.has_path(&path)) {
+            } else if git.repos.iter().any(|e| e.has_path(&path)) {
                 debug!("Skipping {:?} because we already queried it", path);
                 debug!("Skipping {:?} because we already queried it", path);
-            }
-            else {
+            } else {
                 let flags = git2::RepositoryOpenFlags::FROM_ENV;
                 let flags = git2::RepositoryOpenFlags::FROM_ENV;
                 match GitRepo::discover(path, flags) {
                 match GitRepo::discover(path, flags) {
                     Ok(r) => {
                     Ok(r) => {
                         if let Some(r2) = git.repos.iter_mut().find(|e| e.has_workdir(&r.workdir)) {
                         if let Some(r2) = git.repos.iter_mut().find(|e| e.has_workdir(&r.workdir)) {
-                            debug!("Adding to existing repo (workdir matches with {:?})", r2.workdir);
+                            debug!(
+                                "Adding to existing repo (workdir matches with {:?})",
+                                r2.workdir
+                            );
                             r2.extra_paths.push(r.original_path);
                             r2.extra_paths.push(r.original_path);
                             continue;
                             continue;
                         }
                         }
@@ -94,10 +95,8 @@ impl FromIterator<PathBuf> for GitCache {
     }
     }
 }
 }
 
 
-
 /// A **Git repository** is one we’ve discovered somewhere on the filesystem.
 /// A **Git repository** is one we’ve discovered somewhere on the filesystem.
 pub struct GitRepo {
 pub struct GitRepo {
-
     /// The queryable contents of the repository: either a `git2` repo, or the
     /// The queryable contents of the repository: either a `git2` repo, or the
     /// cached results from when we queried it last time.
     /// cached results from when we queried it last time.
     contents: Mutex<GitContents>,
     contents: Mutex<GitContents>,
@@ -118,11 +117,8 @@ pub struct GitRepo {
 
 
 /// A repository’s queried state.
 /// A repository’s queried state.
 enum GitContents {
 enum GitContents {
-
     /// All the interesting Git stuff goes through this.
     /// All the interesting Git stuff goes through this.
-    Before {
-        repo: git2::Repository,
-    },
+    Before { repo: git2::Repository },
 
 
     /// Temporary value used in `repo_to_statuses` so we can move the
     /// Temporary value used in `repo_to_statuses` so we can move the
     /// repository out of the `Before` variant.
     /// repository out of the `Before` variant.
@@ -130,13 +126,10 @@ enum GitContents {
 
 
     /// The data we’ve extracted from the repository, but only after we’ve
     /// The data we’ve extracted from the repository, but only after we’ve
     /// actually done so.
     /// actually done so.
-    After {
-        statuses: Git,
-    },
+    After { statuses: Git },
 }
 }
 
 
 impl GitRepo {
 impl GitRepo {
-
     /// Searches through this repository for a path (to a file or directory,
     /// Searches through this repository for a path (to a file or directory,
     /// depending on the prefix-lookup flag) and returns its Git status.
     /// depending on the prefix-lookup flag) and returns its Git status.
     ///
     ///
@@ -171,7 +164,8 @@ impl GitRepo {
 
 
     /// Whether this repository cares about the given path at all.
     /// Whether this repository cares about the given path at all.
     fn has_path(&self, path: &Path) -> bool {
     fn has_path(&self, path: &Path) -> bool {
-        path.starts_with(&self.original_path) || self.extra_paths.iter().any(|e| path.starts_with(e))
+        path.starts_with(&self.original_path)
+            || self.extra_paths.iter().any(|e| path.starts_with(e))
     }
     }
 
 
     /// Open a Git repository. Depending on the flags, the path is either
     /// Open a Git repository. Depending on the flags, the path is either
@@ -191,16 +185,19 @@ impl GitRepo {
         if let Some(workdir) = repo.workdir() {
         if let Some(workdir) = repo.workdir() {
             let workdir = workdir.to_path_buf();
             let workdir = workdir.to_path_buf();
             let contents = Mutex::new(GitContents::Before { repo });
             let contents = Mutex::new(GitContents::Before { repo });
-            Ok(Self { contents, workdir, original_path: path, extra_paths: Vec::new() })
-        }
-        else {
+            Ok(Self {
+                contents,
+                workdir,
+                original_path: path,
+                extra_paths: Vec::new(),
+            })
+        } else {
             warn!("Repository has no workdir?");
             warn!("Repository has no workdir?");
             Err(path)
             Err(path)
         }
         }
     }
     }
 }
 }
 
 
-
 impl GitContents {
 impl GitContents {
     /// Assumes that the repository hasn’t been queried, and extracts it
     /// Assumes that the repository hasn’t been queried, and extracts it
     /// (consuming the value) if it has. This is needed because the entire
     /// (consuming the value) if it has. This is needed because the entire
@@ -208,8 +205,7 @@ impl GitContents {
     fn inner_repo(self) -> git2::Repository {
     fn inner_repo(self) -> git2::Repository {
         if let Self::Before { repo } = self {
         if let Self::Before { repo } = self {
             repo
             repo
-        }
-        else {
+        } else {
             unreachable!("Tried to extract a non-Repository")
             unreachable!("Tried to extract a non-Repository")
         }
         }
     }
     }
@@ -255,20 +251,21 @@ fn repo_to_statuses(repo: &git2::Repository, workdir: &Path) -> Git {
 // Even inserting another logging line immediately afterwards doesn’t make it
 // Even inserting another logging line immediately afterwards doesn’t make it
 // look any faster.
 // look any faster.
 
 
-
 /// Container of Git statuses for all the files in this folder’s Git repository.
 /// Container of Git statuses for all the files in this folder’s Git repository.
 struct Git {
 struct Git {
     statuses: Vec<(PathBuf, git2::Status)>,
     statuses: Vec<(PathBuf, git2::Status)>,
 }
 }
 
 
 impl Git {
 impl Git {
-
     /// Get either the file or directory status for the given path.
     /// Get either the file or directory status for the given path.
     /// “Prefix lookup” means that it should report an aggregate status of all
     /// “Prefix lookup” means that it should report an aggregate status of all
     /// paths starting with the given prefix (in other words, a directory).
     /// paths starting with the given prefix (in other words, a directory).
     fn status(&self, index: &Path, prefix_lookup: bool) -> f::Git {
     fn status(&self, index: &Path, prefix_lookup: bool) -> f::Git {
-        if prefix_lookup { self.dir_status(index) }
-                    else { self.file_status(index) }
+        if prefix_lookup {
+            self.dir_status(index)
+        } else {
+            self.file_status(index)
+        }
     }
     }
 
 
     /// Get the user-facing status of a file.
     /// Get the user-facing status of a file.
@@ -277,11 +274,15 @@ impl Git {
     fn file_status(&self, file: &Path) -> f::Git {
     fn file_status(&self, file: &Path) -> f::Git {
         let path = reorient(file);
         let path = reorient(file);
 
 
-        let s = self.statuses.iter()
-            .filter(|p| if p.1 == git2::Status::IGNORED {
-                path.starts_with(&p.0)
-            } else {
-                p.0 == path
+        let s = self
+            .statuses
+            .iter()
+            .filter(|p| {
+                if p.1 == git2::Status::IGNORED {
+                    path.starts_with(&p.0)
+                } else {
+                    p.0 == path
+                }
             })
             })
             .fold(git2::Status::empty(), |a, b| a | b.1);
             .fold(git2::Status::empty(), |a, b| a | b.1);
 
 
@@ -298,11 +299,15 @@ impl Git {
     fn dir_status(&self, dir: &Path) -> f::Git {
     fn dir_status(&self, dir: &Path) -> f::Git {
         let path = reorient(dir);
         let path = reorient(dir);
 
 
-        let s = self.statuses.iter()
-            .filter(|p| if p.1 == git2::Status::IGNORED {
-                path.starts_with(&p.0)
-            } else {
-                p.0.starts_with(&path)
+        let s = self
+            .statuses
+            .iter()
+            .filter(|p| {
+                if p.1 == git2::Status::IGNORED {
+                    path.starts_with(&p.0)
+                } else {
+                    p.0.starts_with(&path)
+                }
             })
             })
             .fold(git2::Status::empty(), |a, b| a | b.1);
             .fold(git2::Status::empty(), |a, b| a | b.1);
 
 
@@ -312,7 +317,6 @@ impl Git {
     }
     }
 }
 }
 
 
-
 /// Converts a path to an absolute path based on the current directory.
 /// Converts a path to an absolute path based on the current directory.
 /// Paths need to be absolute for them to be compared properly, otherwise
 /// Paths need to be absolute for them to be compared properly, otherwise
 /// you’d ask a repo about “./README.md” but it only knows about
 /// you’d ask a repo about “./README.md” but it only knows about
@@ -323,8 +327,8 @@ fn reorient(path: &Path) -> PathBuf {
 
 
     // TODO: I’m not 100% on this func tbh
     // TODO: I’m not 100% on this func tbh
     let path = match current_dir() {
     let path = match current_dir() {
-        Err(_)   => Path::new(".").join(path),
-        Ok(dir)  => dir.join(path),
+        Err(_) => Path::new(".").join(path),
+        Ok(dir) => dir.join(path),
     };
     };
 
 
     path.canonicalize().unwrap_or(path)
     path.canonicalize().unwrap_or(path)
@@ -334,13 +338,18 @@ fn reorient(path: &Path) -> PathBuf {
 fn reorient(path: &Path) -> PathBuf {
 fn reorient(path: &Path) -> PathBuf {
     let unc_path = path.canonicalize().unwrap_or_else(|_| path.to_path_buf());
     let unc_path = path.canonicalize().unwrap_or_else(|_| path.to_path_buf());
     // On Windows UNC path is returned. We need to strip the prefix for it to work.
     // On Windows UNC path is returned. We need to strip the prefix for it to work.
-    let normal_path = unc_path.as_os_str().to_str().unwrap().trim_start_matches("\\\\?\\");
+    let normal_path = unc_path
+        .as_os_str()
+        .to_str()
+        .unwrap()
+        .trim_start_matches("\\\\?\\");
     PathBuf::from(normal_path)
     PathBuf::from(normal_path)
 }
 }
 
 
 /// The character to display if the file has been modified, but not staged.
 /// The character to display if the file has been modified, but not staged.
 fn working_tree_status(status: git2::Status) -> f::GitStatus {
 fn working_tree_status(status: git2::Status) -> f::GitStatus {
-    match status {
+    #[rustfmt::skip]
+    return match status {
         s if s.contains(git2::Status::WT_NEW)         => f::GitStatus::New,
         s if s.contains(git2::Status::WT_NEW)         => f::GitStatus::New,
         s if s.contains(git2::Status::WT_MODIFIED)    => f::GitStatus::Modified,
         s if s.contains(git2::Status::WT_MODIFIED)    => f::GitStatus::Modified,
         s if s.contains(git2::Status::WT_DELETED)     => f::GitStatus::Deleted,
         s if s.contains(git2::Status::WT_DELETED)     => f::GitStatus::Deleted,
@@ -349,37 +358,43 @@ fn working_tree_status(status: git2::Status) -> f::GitStatus {
         s if s.contains(git2::Status::IGNORED)        => f::GitStatus::Ignored,
         s if s.contains(git2::Status::IGNORED)        => f::GitStatus::Ignored,
         s if s.contains(git2::Status::CONFLICTED)     => f::GitStatus::Conflicted,
         s if s.contains(git2::Status::CONFLICTED)     => f::GitStatus::Conflicted,
         _                                             => f::GitStatus::NotModified,
         _                                             => f::GitStatus::NotModified,
-    }
+    };
 }
 }
 
 
 /// The character to display if the file has been modified and the change
 /// The character to display if the file has been modified and the change
 /// has been staged.
 /// has been staged.
 fn index_status(status: git2::Status) -> f::GitStatus {
 fn index_status(status: git2::Status) -> f::GitStatus {
-    match status {
+    #[rustfmt::skip]
+    return match status {
         s if s.contains(git2::Status::INDEX_NEW)         => f::GitStatus::New,
         s if s.contains(git2::Status::INDEX_NEW)         => f::GitStatus::New,
         s if s.contains(git2::Status::INDEX_MODIFIED)    => f::GitStatus::Modified,
         s if s.contains(git2::Status::INDEX_MODIFIED)    => f::GitStatus::Modified,
         s if s.contains(git2::Status::INDEX_DELETED)     => f::GitStatus::Deleted,
         s if s.contains(git2::Status::INDEX_DELETED)     => f::GitStatus::Deleted,
         s if s.contains(git2::Status::INDEX_RENAMED)     => f::GitStatus::Renamed,
         s if s.contains(git2::Status::INDEX_RENAMED)     => f::GitStatus::Renamed,
         s if s.contains(git2::Status::INDEX_TYPECHANGE)  => f::GitStatus::TypeChange,
         s if s.contains(git2::Status::INDEX_TYPECHANGE)  => f::GitStatus::TypeChange,
         _                                                => f::GitStatus::NotModified,
         _                                                => f::GitStatus::NotModified,
-    }
+    };
 }
 }
 
 
-fn current_branch(repo: &git2::Repository) -> Option<String>{
+fn current_branch(repo: &git2::Repository) -> Option<String> {
     let head = match repo.head() {
     let head = match repo.head() {
         Ok(head) => Some(head),
         Ok(head) => Some(head),
-        Err(ref e) if e.code() == git2::ErrorCode::UnbornBranch || e.code() == git2::ErrorCode::NotFound => return None,
+        Err(ref e)
+            if e.code() == git2::ErrorCode::UnbornBranch
+                || e.code() == git2::ErrorCode::NotFound =>
+        {
+            return None
+        }
         Err(e) => {
         Err(e) => {
             error!("Error looking up Git branch: {:?}", e);
             error!("Error looking up Git branch: {:?}", e);
-            return None
+            return None;
         }
         }
     };
     };
 
 
-    if let Some(h) = head{
-        if let Some(s) = h.shorthand(){
+    if let Some(h) = head {
+        if let Some(s) = h.shorthand() {
             let branch_name = s.to_owned();
             let branch_name = s.to_owned();
             if branch_name.len() > 10 {
             if branch_name.len() > 10 {
-               return Some(branch_name[..8].to_string()+"..");
+                return Some(branch_name[..8].to_string() + "..");
             }
             }
             return Some(branch_name);
             return Some(branch_name);
         }
         }
@@ -387,21 +402,30 @@ fn current_branch(repo: &git2::Repository) -> Option<String>{
     None
     None
 }
 }
 
 
-impl f::SubdirGitRepo{
-    pub fn from_path(dir : &Path, status : bool) -> Self{
+impl f::SubdirGitRepo {
+    pub fn from_path(dir: &Path, status: bool) -> Self {
         let path = &reorient(dir);
         let path = &reorient(dir);
 
 
         if let Ok(repo) = git2::Repository::open(path) {
         if let Ok(repo) = git2::Repository::open(path) {
             let branch = current_branch(&repo);
             let branch = current_branch(&repo);
-            if !status{
-                return Self{ status: None, branch };
+            if !status {
+                return Self {
+                    status: None,
+                    branch,
+                };
             }
             }
             match repo.statuses(None) {
             match repo.statuses(None) {
                 Ok(es) => {
                 Ok(es) => {
                     if es.iter().any(|s| s.status() != git2::Status::IGNORED) {
                     if es.iter().any(|s| s.status() != git2::Status::IGNORED) {
-                        return Self { status: Some(f::SubdirGitRepoStatus::GitDirty), branch };
+                        return Self {
+                            status: Some(f::SubdirGitRepoStatus::GitDirty),
+                            branch,
+                        };
                     }
                     }
-                    return Self { status: Some(f::SubdirGitRepoStatus::GitClean), branch };
+                    return Self {
+                        status: Some(f::SubdirGitRepoStatus::GitClean),
+                        branch,
+                    };
                 }
                 }
                 Err(e) => {
                 Err(e) => {
                     error!("Error looking up Git statuses: {e:?}");
                     error!("Error looking up Git statuses: {e:?}");
@@ -409,7 +433,11 @@ impl f::SubdirGitRepo{
             }
             }
         }
         }
         f::SubdirGitRepo {
         f::SubdirGitRepo {
-            status: if status { Some(f::SubdirGitRepoStatus::NoRepo) } else { None },
+            status: if status {
+                Some(f::SubdirGitRepoStatus::NoRepo)
+            } else {
+                None
+            },
             branch: None,
             branch: None,
         }
         }
     }
     }

+ 4 - 4
src/fs/feature/mod.rs

@@ -10,12 +10,12 @@ pub mod git {
 
 
     use crate::fs::fields as f;
     use crate::fs::fields as f;
 
 
-
     pub struct GitCache;
     pub struct GitCache;
 
 
     impl FromIterator<PathBuf> for GitCache {
     impl FromIterator<PathBuf> for GitCache {
         fn from_iter<I>(_iter: I) -> Self
         fn from_iter<I>(_iter: I) -> Self
-        where I: IntoIterator<Item=PathBuf>
+        where
+            I: IntoIterator<Item = PathBuf>,
         {
         {
             Self
             Self
         }
         }
@@ -31,8 +31,8 @@ pub mod git {
         }
         }
     }
     }
 
 
-    impl f::SubdirGitRepo{
-        pub fn from_path(_dir : &Path, _status : bool) -> Self{
+    impl f::SubdirGitRepo {
+        pub fn from_path(_dir: &Path, _status: bool) -> Self {
             panic!("Tried to get subdir Git status, but Git support is disabled")
             panic!("Tried to get subdir Git status, but Git support is disabled")
         }
         }
     }
     }

+ 70 - 84
src/fs/feature/xattr.rs

@@ -1,6 +1,6 @@
 //! Extended attribute support for Darwin and Linux systems.
 //! Extended attribute support for Darwin and Linux systems.
 
 
-#![allow(trivial_casts)]  // for ARM
+#![allow(trivial_casts)] // for ARM
 
 
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 use std::cmp::Ordering;
 use std::cmp::Ordering;
@@ -9,10 +9,8 @@ use std::ffi::CString;
 use std::io;
 use std::io;
 use std::path::Path;
 use std::path::Path;
 
 
-
 pub const ENABLED: bool = cfg!(any(target_os = "macos", target_os = "linux"));
 pub const ENABLED: bool = cfg!(any(target_os = "macos", target_os = "linux"));
 
 
-
 pub trait FileAttributes {
 pub trait FileAttributes {
     fn attributes(&self) -> io::Result<Vec<Attribute>>;
     fn attributes(&self) -> io::Result<Vec<Attribute>>;
     fn symlink_attributes(&self) -> io::Result<Vec<Attribute>>;
     fn symlink_attributes(&self) -> io::Result<Vec<Attribute>>;
@@ -40,7 +38,6 @@ impl FileAttributes for Path {
     }
     }
 }
 }
 
 
-
 /// Attributes which can be passed to `Attribute::list_with_flags`
 /// Attributes which can be passed to `Attribute::list_with_flags`
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
@@ -56,15 +53,13 @@ pub struct Attribute {
     pub value: String,
     pub value: String,
 }
 }
 
 
-
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 fn get_secattr(lister: &lister::Lister, c_path: &std::ffi::CString) -> io::Result<Vec<Attribute>> {
 fn get_secattr(lister: &lister::Lister, c_path: &std::ffi::CString) -> io::Result<Vec<Attribute>> {
     const SELINUX_XATTR_NAME: &str = "security.selinux";
     const SELINUX_XATTR_NAME: &str = "security.selinux";
     const ENODATA: i32 = 61;
     const ENODATA: i32 = 61;
 
 
-    let c_attr_name = CString::new(SELINUX_XATTR_NAME).map_err(|e| {
-        io::Error::new(io::ErrorKind::Other, e)
-    })?;
+    let c_attr_name =
+        CString::new(SELINUX_XATTR_NAME).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
     let size = lister.getxattr_first(c_path, &c_attr_name);
     let size = lister.getxattr_first(c_path, &c_attr_name);
 
 
     let size = match size.cmp(&0) {
     let size = match size.cmp(&0) {
@@ -72,11 +67,11 @@ fn get_secattr(lister: &lister::Lister, c_path: &std::ffi::CString) -> io::Resul
             let e = io::Error::last_os_error();
             let e = io::Error::last_os_error();
 
 
             if e.kind() == io::ErrorKind::Other && e.raw_os_error() == Some(ENODATA) {
             if e.kind() == io::ErrorKind::Other && e.raw_os_error() == Some(ENODATA) {
-                return Ok(Vec::new())
+                return Ok(Vec::new());
             }
             }
 
 
-            return Err(e)
-        },
+            return Err(e);
+        }
         Ordering::Equal => return Err(io::Error::from(io::ErrorKind::InvalidData)),
         Ordering::Equal => return Err(io::Error::from(io::ErrorKind::InvalidData)),
         Ordering::Greater => size as usize,
         Ordering::Greater => size as usize,
     };
     };
@@ -91,32 +86,34 @@ fn get_secattr(lister: &lister::Lister, c_path: &std::ffi::CString) -> io::Resul
     }
     }
 
 
     Ok(vec![Attribute {
     Ok(vec![Attribute {
-        name:  String::from(SELINUX_XATTR_NAME),
+        name: String::from(SELINUX_XATTR_NAME),
         value: lister.translate_attribute_data(&buf_value),
         value: lister.translate_attribute_data(&buf_value),
     }])
     }])
 }
 }
 
 
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 pub fn list_attrs(lister: &lister::Lister, path: &Path) -> io::Result<Vec<Attribute>> {
 pub fn list_attrs(lister: &lister::Lister, path: &Path) -> io::Result<Vec<Attribute>> {
-    let c_path = CString::new(path.to_str().ok_or(io::Error::new(io::ErrorKind::Other, "Error: path not convertible to string"))?).map_err(|e| {
-        io::Error::new(io::ErrorKind::Other, e)
-    })?;
+    let c_path = CString::new(path.to_str().ok_or(io::Error::new(
+        io::ErrorKind::Other,
+        "Error: path not convertible to string",
+    ))?)
+    .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
 
 
     let bufsize = lister.listxattr_first(&c_path);
     let bufsize = lister.listxattr_first(&c_path);
     let bufsize = match bufsize.cmp(&0) {
     let bufsize = match bufsize.cmp(&0) {
-        Ordering::Less     => return Err(io::Error::last_os_error()),
+        Ordering::Less => return Err(io::Error::last_os_error()),
         // Some filesystems, like sysfs, return nothing on listxattr, even though the security
         // Some filesystems, like sysfs, return nothing on listxattr, even though the security
         // attribute is set.
         // attribute is set.
-        Ordering::Equal    => return get_secattr(lister, &c_path),
-        Ordering::Greater  => bufsize as usize,
+        Ordering::Equal => return get_secattr(lister, &c_path),
+        Ordering::Greater => bufsize as usize,
     };
     };
 
 
     let mut buf = vec![0_u8; bufsize];
     let mut buf = vec![0_u8; bufsize];
 
 
     match lister.listxattr_second(&c_path, &mut buf, bufsize).cmp(&0) {
     match lister.listxattr_second(&c_path, &mut buf, bufsize).cmp(&0) {
-        Ordering::Less     => return Err(io::Error::last_os_error()),
-        Ordering::Equal    => return Ok(Vec::new()),
-        Ordering::Greater  => {},
+        Ordering::Less => return Err(io::Error::last_os_error()),
+        Ordering::Equal => return Ok(Vec::new()),
+        Ordering::Greater => {}
     }
     }
 
 
     let mut names = Vec::new();
     let mut names = Vec::new();
@@ -126,9 +123,8 @@ pub fn list_attrs(lister: &lister::Lister, path: &Path) -> io::Result<Vec<Attrib
             continue;
             continue;
         }
         }
 
 
-        let c_attr_name = CString::new(attr_name).map_err(|e| {
-            io::Error::new(io::ErrorKind::Other, e)
-        })?;
+        let c_attr_name =
+            CString::new(attr_name).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
         let size = lister.getxattr_first(&c_path, &c_attr_name);
         let size = lister.getxattr_first(&c_path, &c_attr_name);
 
 
         if size > 0 {
         if size > 0 {
@@ -138,12 +134,12 @@ pub fn list_attrs(lister: &lister::Lister, path: &Path) -> io::Result<Vec<Attrib
             }
             }
 
 
             names.push(Attribute {
             names.push(Attribute {
-                name:  lister.translate_attribute_data(attr_name),
+                name: lister.translate_attribute_data(attr_name),
                 value: lister.translate_attribute_data(&buf_value),
                 value: lister.translate_attribute_data(&buf_value),
             });
             });
         } else {
         } else {
             names.push(Attribute {
             names.push(Attribute {
-                name:  lister.translate_attribute_data(attr_name),
+                name: lister.translate_attribute_data(attr_name),
                 value: String::new(),
                 value: String::new(),
             });
             });
         }
         }
@@ -152,11 +148,10 @@ pub fn list_attrs(lister: &lister::Lister, path: &Path) -> io::Result<Vec<Attrib
     Ok(names)
     Ok(names)
 }
 }
 
 
-
 #[cfg(target_os = "macos")]
 #[cfg(target_os = "macos")]
 mod lister {
 mod lister {
     use super::FollowSymlinks;
     use super::FollowSymlinks;
-    use libc::{c_int, size_t, ssize_t, c_char, c_void};
+    use libc::{c_char, c_int, c_void, size_t, ssize_t};
     use std::ffi::CString;
     use std::ffi::CString;
     use std::ptr;
     use std::ptr;
 
 
@@ -185,29 +180,31 @@ mod lister {
     impl Lister {
     impl Lister {
         pub fn new(do_follow: FollowSymlinks) -> Self {
         pub fn new(do_follow: FollowSymlinks) -> Self {
             let c_flags: c_int = match do_follow {
             let c_flags: c_int = match do_follow {
-                FollowSymlinks::Yes  => 0x0001,
-                FollowSymlinks::No   => 0x0000,
+                FollowSymlinks::Yes => 0x0001,
+                FollowSymlinks::No => 0x0000,
             };
             };
 
 
             Self { c_flags }
             Self { c_flags }
         }
         }
 
 
         pub fn translate_attribute_data(&self, input: &[u8]) -> String {
         pub fn translate_attribute_data(&self, input: &[u8]) -> String {
-            unsafe { std::str::from_utf8_unchecked(input).trim_end_matches('\0').into() }
+            unsafe {
+                std::str::from_utf8_unchecked(input)
+                    .trim_end_matches('\0')
+                    .into()
+            }
         }
         }
 
 
         pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
         pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
-            unsafe {
-                listxattr(
-                    c_path.as_ptr(),
-                    ptr::null_mut(),
-                    0,
-                    self.c_flags,
-                )
-            }
+            unsafe { listxattr(c_path.as_ptr(), ptr::null_mut(), 0, self.c_flags) }
         }
         }
 
 
-        pub fn listxattr_second(&self, c_path: &CString, buf: &mut [u8], bufsize: size_t) -> ssize_t {
+        pub fn listxattr_second(
+            &self,
+            c_path: &CString,
+            buf: &mut [u8],
+            bufsize: size_t,
+        ) -> ssize_t {
             unsafe {
             unsafe {
                 listxattr(
                 listxattr(
                     c_path.as_ptr(),
                     c_path.as_ptr(),
@@ -231,7 +228,13 @@ mod lister {
             }
             }
         }
         }
 
 
-        pub fn getxattr_second(&self, c_path: &CString, c_name: &CString, buf: &mut [u8], bufsize: size_t) -> ssize_t {
+        pub fn getxattr_second(
+            &self,
+            c_path: &CString,
+            c_name: &CString,
+            buf: &mut [u8],
+            bufsize: size_t,
+        ) -> ssize_t {
             unsafe {
             unsafe {
                 getxattr(
                 getxattr(
                     c_path.as_ptr(),
                     c_path.as_ptr(),
@@ -246,26 +249,17 @@ mod lister {
     }
     }
 }
 }
 
 
-
 #[cfg(target_os = "linux")]
 #[cfg(target_os = "linux")]
 mod lister {
 mod lister {
-    use std::ffi::CString;
-    use libc::{size_t, ssize_t, c_char, c_void};
     use super::FollowSymlinks;
     use super::FollowSymlinks;
+    use libc::{c_char, c_void, size_t, ssize_t};
+    use std::ffi::CString;
     use std::ptr;
     use std::ptr;
 
 
     extern "C" {
     extern "C" {
-        fn listxattr(
-            path: *const c_char,
-            list: *mut c_char,
-            size: size_t,
-        ) -> ssize_t;
+        fn listxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t;
 
 
-        fn llistxattr(
-            path: *const c_char,
-            list: *mut c_char,
-            size: size_t,
-        ) -> ssize_t;
+        fn llistxattr(path: *const c_char, list: *mut c_char, size: size_t) -> ssize_t;
 
 
         fn getxattr(
         fn getxattr(
             path: *const c_char,
             path: *const c_char,
@@ -297,54 +291,46 @@ mod lister {
 
 
         pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
         pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
             let listxattr = match self.follow_symlinks {
             let listxattr = match self.follow_symlinks {
-                FollowSymlinks::Yes  => listxattr,
-                FollowSymlinks::No   => llistxattr,
+                FollowSymlinks::Yes => listxattr,
+                FollowSymlinks::No => llistxattr,
             };
             };
 
 
-            unsafe {
-                listxattr(
-                    c_path.as_ptr(),
-                    ptr::null_mut(),
-                    0,
-                )
-            }
+            unsafe { listxattr(c_path.as_ptr(), ptr::null_mut(), 0) }
         }
         }
 
 
-        pub fn listxattr_second(&self, c_path: &CString, buf: &mut [u8], bufsize: size_t) -> ssize_t {
+        pub fn listxattr_second(
+            &self,
+            c_path: &CString,
+            buf: &mut [u8],
+            bufsize: size_t,
+        ) -> ssize_t {
             let listxattr = match self.follow_symlinks {
             let listxattr = match self.follow_symlinks {
-                FollowSymlinks::Yes  => listxattr,
-                FollowSymlinks::No   => llistxattr,
+                FollowSymlinks::Yes => listxattr,
+                FollowSymlinks::No => llistxattr,
             };
             };
 
 
-            unsafe {
-                listxattr(
-                    c_path.as_ptr(),
-                    buf.as_mut_ptr().cast(),
-                    bufsize,
-                )
-            }
+            unsafe { listxattr(c_path.as_ptr(), buf.as_mut_ptr().cast(), bufsize) }
         }
         }
 
 
         pub fn getxattr_first(&self, c_path: &CString, c_name: &CString) -> ssize_t {
         pub fn getxattr_first(&self, c_path: &CString, c_name: &CString) -> ssize_t {
             let getxattr = match self.follow_symlinks {
             let getxattr = match self.follow_symlinks {
                 FollowSymlinks::Yes => getxattr,
                 FollowSymlinks::Yes => getxattr,
-                FollowSymlinks::No  => lgetxattr,
+                FollowSymlinks::No => lgetxattr,
             };
             };
 
 
-            unsafe {
-                getxattr(
-                    c_path.as_ptr(),
-                    c_name.as_ptr().cast(),
-                    ptr::null_mut(),
-                    0,
-                )
-            }
+            unsafe { getxattr(c_path.as_ptr(), c_name.as_ptr().cast(), ptr::null_mut(), 0) }
         }
         }
 
 
-        pub fn getxattr_second(&self, c_path: &CString, c_name: &CString, buf: &mut [u8], bufsize: size_t) -> ssize_t {
+        pub fn getxattr_second(
+            &self,
+            c_path: &CString,
+            c_name: &CString,
+            buf: &mut [u8],
+            bufsize: size_t,
+        ) -> ssize_t {
             let getxattr = match self.follow_symlinks {
             let getxattr = match self.follow_symlinks {
                 FollowSymlinks::Yes => getxattr,
                 FollowSymlinks::Yes => getxattr,
-                FollowSymlinks::No  => lgetxattr,
+                FollowSymlinks::No => lgetxattr,
             };
             };
 
 
             unsafe {
             unsafe {

+ 14 - 27
src/fs/fields.rs

@@ -29,7 +29,6 @@ pub type time_t = i64;
 /// The type of a file’s user ID.
 /// The type of a file’s user ID.
 pub type uid_t = u32;
 pub type uid_t = u32;
 
 
-
 /// The file’s base type, which gets displayed in the very first column of the
 /// The file’s base type, which gets displayed in the very first column of the
 /// details output.
 /// details output.
 ///
 ///
@@ -56,9 +55,9 @@ impl Type {
     }
     }
 }
 }
 
 
-
 /// The file’s Unix permission bitfield, with one entry per bit.
 /// The file’s Unix permission bitfield, with one entry per bit.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
+#[rustfmt::skip]
 pub struct Permissions {
 pub struct Permissions {
     pub user_read:      bool,
     pub user_read:      bool,
     pub user_write:     bool,
     pub user_write:     bool,
@@ -79,6 +78,7 @@ pub struct Permissions {
 
 
 /// The file's `FileAttributes` field, available only on Windows.
 /// The file's `FileAttributes` field, available only on Windows.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
+#[rustfmt::skip]
 pub struct Attributes {
 pub struct Attributes {
     pub archive:         bool,
     pub archive:         bool,
     pub directory:       bool,
     pub directory:       bool,
@@ -93,15 +93,14 @@ pub struct Attributes {
 /// little more compressed.
 /// little more compressed.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
 pub struct PermissionsPlus {
 pub struct PermissionsPlus {
-    pub file_type:   Type,
+    pub file_type: Type,
     #[cfg(unix)]
     #[cfg(unix)]
     pub permissions: Permissions,
     pub permissions: Permissions,
     #[cfg(windows)]
     #[cfg(windows)]
-    pub attributes:  Attributes,
-    pub xattrs:      bool,
+    pub attributes: Attributes,
+    pub xattrs: bool,
 }
 }
 
 
-
 /// The permissions encoded as octal values
 /// The permissions encoded as octal values
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
 pub struct OctalPermissions {
 pub struct OctalPermissions {
@@ -116,7 +115,6 @@ pub struct OctalPermissions {
 /// block count specifically for this case.
 /// block count specifically for this case.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
 pub struct Links {
 pub struct Links {
-
     /// The actual link count.
     /// The actual link count.
     pub count: nlink_t,
     pub count: nlink_t,
 
 
@@ -124,19 +122,16 @@ pub struct Links {
     pub multiple: bool,
     pub multiple: bool,
 }
 }
 
 
-
 /// A file’s inode. Every directory entry on a Unix filesystem has an inode,
 /// A file’s inode. Every directory entry on a Unix filesystem has an inode,
 /// including directories and links, so this is applicable to everything exa
 /// including directories and links, so this is applicable to everything exa
 /// can deal with.
 /// can deal with.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
 pub struct Inode(pub ino_t);
 pub struct Inode(pub ino_t);
 
 
-
 /// A file's size of allocated file system blocks.
 /// A file's size of allocated file system blocks.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
 #[cfg(unix)]
 #[cfg(unix)]
 pub enum Blocksize {
 pub enum Blocksize {
-
     /// This file has the given number of blocks.
     /// This file has the given number of blocks.
     Some(u64),
     Some(u64),
 
 
@@ -144,7 +139,6 @@ pub enum Blocksize {
     None,
     None,
 }
 }
 
 
-
 /// The ID of the user that owns a file. This will only ever be a number;
 /// The ID of the user that owns a file. This will only ever be a number;
 /// looking up the username is done in the `display` module.
 /// looking up the username is done in the `display` module.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
@@ -154,12 +148,10 @@ pub struct User(pub uid_t);
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
 pub struct Group(pub gid_t);
 pub struct Group(pub gid_t);
 
 
-
 /// A file’s size, in bytes. This is usually formatted by the `number_prefix`
 /// A file’s size, in bytes. This is usually formatted by the `number_prefix`
 /// crate into something human-readable.
 /// crate into something human-readable.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
 pub enum Size {
 pub enum Size {
-
     /// This file has a defined size.
     /// This file has a defined size.
     Some(u64),
     Some(u64),
 
 
@@ -194,7 +186,6 @@ pub struct DeviceIDs {
     pub minor: u32,
     pub minor: u32,
 }
 }
 
 
-
 /// One of a file’s timestamps (created, accessed, or modified).
 /// One of a file’s timestamps (created, accessed, or modified).
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Time {
 pub struct Time {
@@ -202,13 +193,11 @@ pub struct Time {
     pub nanoseconds: time_t,
     pub nanoseconds: time_t,
 }
 }
 
 
-
 /// A file’s status in a Git repository. Whether a file is in a repository or
 /// A file’s status in a Git repository. Whether a file is in a repository or
 /// not is handled by the Git module, rather than having a “null” variant in
 /// not is handled by the Git module, rather than having a “null” variant in
 /// this enum.
 /// this enum.
 #[derive(PartialEq, Eq, Copy, Clone)]
 #[derive(PartialEq, Eq, Copy, Clone)]
 pub enum GitStatus {
 pub enum GitStatus {
-
     /// This file hasn’t changed since the last commit.
     /// This file hasn’t changed since the last commit.
     NotModified,
     NotModified,
 
 
@@ -235,18 +224,16 @@ pub enum GitStatus {
     Conflicted,
     Conflicted,
 }
 }
 
 
-
 /// A file’s complete Git status. It’s possible to make changes to a file, add
 /// A file’s complete Git status. It’s possible to make changes to a file, add
 /// it to the staging area, then make *more* changes, so we need to list each
 /// it to the staging area, then make *more* changes, so we need to list each
 /// file’s status for both of these.
 /// file’s status for both of these.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
 pub struct Git {
 pub struct Git {
-    pub staged:   GitStatus,
+    pub staged: GitStatus,
     pub unstaged: GitStatus,
     pub unstaged: GitStatus,
 }
 }
 
 
 impl Default for Git {
 impl Default for Git {
-
     /// Create a Git status for a file with nothing done to it.
     /// Create a Git status for a file with nothing done to it.
     fn default() -> Self {
     fn default() -> Self {
         Self {
         Self {
@@ -258,7 +245,7 @@ impl Default for Git {
 
 
 pub enum SecurityContextType<'a> {
 pub enum SecurityContextType<'a> {
     SELinux(&'a str),
     SELinux(&'a str),
-    None
+    None,
 }
 }
 
 
 pub struct SecurityContext<'a> {
 pub struct SecurityContext<'a> {
@@ -267,23 +254,23 @@ pub struct SecurityContext<'a> {
 
 
 #[allow(dead_code)]
 #[allow(dead_code)]
 #[derive(PartialEq, Copy, Clone)]
 #[derive(PartialEq, Copy, Clone)]
-pub enum SubdirGitRepoStatus{
+pub enum SubdirGitRepoStatus {
     NoRepo,
     NoRepo,
     GitClean,
     GitClean,
     GitDirty,
     GitDirty,
 }
 }
 
 
 #[derive(Clone)]
 #[derive(Clone)]
-pub struct SubdirGitRepo{
-    pub status : Option<SubdirGitRepoStatus>,
-    pub branch : Option<String>
+pub struct SubdirGitRepo {
+    pub status: Option<SubdirGitRepoStatus>,
+    pub branch: Option<String>,
 }
 }
 
 
-impl Default for SubdirGitRepo{
+impl Default for SubdirGitRepo {
     fn default() -> Self {
     fn default() -> Self {
-        Self{
+        Self {
             status: Some(SubdirGitRepoStatus::NoRepo),
             status: Some(SubdirGitRepoStatus::NoRepo),
-            branch: None
+            branch: None,
         }
         }
     }
     }
 }
 }

+ 153 - 125
src/fs/file.rs

@@ -14,13 +14,12 @@ use log::*;
 
 
 use crate::fs::dir::Dir;
 use crate::fs::dir::Dir;
 use crate::fs::feature::xattr;
 use crate::fs::feature::xattr;
-use crate::fs::feature::xattr::{FileAttributes, Attribute};
+use crate::fs::feature::xattr::{Attribute, FileAttributes};
 use crate::fs::fields as f;
 use crate::fs::fields as f;
 
 
 use super::mounts::all_mounts;
 use super::mounts::all_mounts;
 use super::mounts::MountedFs;
 use super::mounts::MountedFs;
 
 
-
 /// A **File** is a wrapper around one of Rust’s `PathBuf` values, along with
 /// A **File** is a wrapper around one of Rust’s `PathBuf` values, along with
 /// associated data about the file.
 /// associated data about the file.
 ///
 ///
@@ -29,7 +28,6 @@ use super::mounts::MountedFs;
 /// information queried at least once, so it makes sense to do all this at the
 /// information queried at least once, so it makes sense to do all this at the
 /// start and hold on to all the information.
 /// start and hold on to all the information.
 pub struct File<'dir> {
 pub struct File<'dir> {
-
     /// The filename portion of this file’s path, including the extension.
     /// The filename portion of this file’s path, including the extension.
     ///
     ///
     /// This is used to compare against certain filenames (such as checking if
     /// This is used to compare against certain filenames (such as checking if
@@ -89,48 +87,84 @@ pub struct File<'dir> {
 }
 }
 
 
 impl<'dir> File<'dir> {
 impl<'dir> File<'dir> {
-    pub fn from_args<PD, FN>(path: PathBuf, parent_dir: PD, filename: FN, deref_links: bool) -> io::Result<File<'dir>>
-    where PD: Into<Option<&'dir Dir>>,
-          FN: Into<Option<String>>
+    pub fn from_args<PD, FN>(
+        path: PathBuf,
+        parent_dir: PD,
+        filename: FN,
+        deref_links: bool,
+    ) -> io::Result<File<'dir>>
+    where
+        PD: Into<Option<&'dir Dir>>,
+        FN: Into<Option<String>>,
     {
     {
         let parent_dir = parent_dir.into();
         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);
         debug!("Statting file {:?}", &path);
-        let metadata   = std::fs::symlink_metadata(&path)?;
+        let metadata = std::fs::symlink_metadata(&path)?;
         let is_all_all = false;
         let is_all_all = false;
         let extended_attributes = OnceLock::new();
         let extended_attributes = OnceLock::new();
         let absolute_path = OnceLock::new();
         let absolute_path = OnceLock::new();
 
 
-        Ok(File { name, ext, path, metadata, parent_dir, is_all_all, deref_links, extended_attributes, absolute_path })
+        Ok(File {
+            name,
+            ext,
+            path,
+            metadata,
+            parent_dir,
+            is_all_all,
+            deref_links,
+            extended_attributes,
+            absolute_path,
+        })
     }
     }
 
 
     pub fn new_aa_current(parent_dir: &'dir Dir) -> io::Result<File<'dir>> {
     pub fn new_aa_current(parent_dir: &'dir Dir) -> io::Result<File<'dir>> {
-        let path       = parent_dir.path.clone();
-        let ext        = File::ext(&path);
+        let path = parent_dir.path.clone();
+        let ext = File::ext(&path);
 
 
         debug!("Statting file {:?}", &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 is_all_all = true;
         let parent_dir = Some(parent_dir);
         let parent_dir = Some(parent_dir);
         let extended_attributes = OnceLock::new();
         let extended_attributes = OnceLock::new();
         let absolute_path = OnceLock::new();
         let absolute_path = OnceLock::new();
 
 
-        Ok(File { path, parent_dir, metadata, ext, name: ".".into(), is_all_all, deref_links: false, extended_attributes, absolute_path })
+        Ok(File {
+            path,
+            parent_dir,
+            metadata,
+            ext,
+            name: ".".into(),
+            is_all_all,
+            deref_links: false,
+            extended_attributes,
+            absolute_path,
+        })
     }
     }
 
 
     pub fn new_aa_parent(path: PathBuf, parent_dir: &'dir Dir) -> io::Result<File<'dir>> {
     pub fn new_aa_parent(path: PathBuf, parent_dir: &'dir Dir) -> io::Result<File<'dir>> {
-        let ext        = File::ext(&path);
+        let ext = File::ext(&path);
 
 
         debug!("Statting file {:?}", &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 is_all_all = true;
         let parent_dir = Some(parent_dir);
         let parent_dir = Some(parent_dir);
         let extended_attributes = OnceLock::new();
         let extended_attributes = OnceLock::new();
         let absolute_path = OnceLock::new();
         let absolute_path = OnceLock::new();
 
 
-        Ok(File { path, parent_dir, metadata, ext, name: "..".into(), is_all_all, deref_links: false, extended_attributes, absolute_path })
+        Ok(File {
+            path,
+            parent_dir,
+            metadata,
+            ext,
+            name: "..".into(),
+            is_all_all,
+            deref_links: false,
+            extended_attributes,
+            absolute_path,
+        })
     }
     }
 
 
     /// A file’s name is derived from its string. This needs to handle directories
     /// A file’s name is derived from its string. This needs to handle directories
@@ -139,8 +173,7 @@ impl<'dir> File<'dir> {
     pub fn filename(path: &Path) -> String {
     pub fn filename(path: &Path) -> String {
         if let Some(back) = path.components().next_back() {
         if let Some(back) = path.components().next_back() {
             back.as_os_str().to_string_lossy().to_string()
             back.as_os_str().to_string_lossy().to_string()
-        }
-        else {
+        } else {
             // use the path as fallback
             // use the path as fallback
             error!("Path {:?} has no last component", path);
             error!("Path {:?} has no last component", path);
             path.display().to_string()
             path.display().to_string()
@@ -158,9 +191,7 @@ impl<'dir> File<'dir> {
     fn ext(path: &Path) -> Option<String> {
     fn ext(path: &Path) -> Option<String> {
         let name = path.file_name().map(|f| f.to_string_lossy().to_string())?;
         let name = path.file_name().map(|f| f.to_string_lossy().to_string())?;
 
 
-        name.rfind('.')
-            .map(|p| name[p + 1 ..]
-            .to_ascii_lowercase())
+        name.rfind('.').map(|p| name[p + 1..].to_ascii_lowercase())
     }
     }
 
 
     /// Read the extended attributes of a file path.
     /// Read the extended attributes of a file path.
@@ -169,7 +200,11 @@ impl<'dir> File<'dir> {
             match path.symlink_attributes() {
             match path.symlink_attributes() {
                 Ok(xattrs) => xattrs,
                 Ok(xattrs) => xattrs,
                 Err(e) => {
                 Err(e) => {
-                    error!("Error looking up extended attributes for {}: {}", path.display(), e);
+                    error!(
+                        "Error looking up extended attributes for {}: {}",
+                        path.display(),
+                        e
+                    );
                     Vec::new()
                     Vec::new()
                 }
                 }
             }
             }
@@ -180,7 +215,8 @@ impl<'dir> File<'dir> {
 
 
     /// Get the extended attributes of a file path on demand.
     /// Get the extended attributes of a file path on demand.
     pub fn extended_attributes(&self) -> &Vec<Attribute> {
     pub fn extended_attributes(&self) -> &Vec<Attribute> {
-        self.extended_attributes.get_or_init(||File::gather_extended_attributes(&self.path))
+        self.extended_attributes
+            .get_or_init(|| File::gather_extended_attributes(&self.path))
     }
     }
 
 
     /// Whether this file is a directory on the filesystem.
     /// Whether this file is a directory on the filesystem.
@@ -261,19 +297,23 @@ impl<'dir> File<'dir> {
 
 
     /// Determine the full path resolving all symbolic links on demand.
     /// Determine the full path resolving all symbolic links on demand.
     pub fn absolute_path(&self) -> Option<&PathBuf> {
     pub fn absolute_path(&self) -> Option<&PathBuf> {
-        self.absolute_path.get_or_init(|| std::fs::canonicalize(&self.path).ok()).as_ref()
+        self.absolute_path
+            .get_or_init(|| std::fs::canonicalize(&self.path).ok())
+            .as_ref()
     }
     }
 
 
     /// Whether this file is a mount point
     /// Whether this file is a mount point
     pub fn is_mount_point(&self) -> bool {
     pub fn is_mount_point(&self) -> bool {
-        cfg!(any(target_os = "linux", target_os = "macos")) &&
-            self.is_directory() &&
-            self.absolute_path().is_some_and(|p| all_mounts().contains_key(p))
+        cfg!(any(target_os = "linux", target_os = "macos"))
+            && self.is_directory()
+            && self
+                .absolute_path()
+                .is_some_and(|p| all_mounts().contains_key(p))
     }
     }
 
 
     /// The filesystem device and type for a mount point
     /// The filesystem device and type for a mount point
     pub fn mount_point_info(&self) -> Option<&MountedFs> {
     pub fn mount_point_info(&self) -> Option<&MountedFs> {
-        if cfg!(any(target_os = "linux",target_os = "macos")) {
+        if cfg!(any(target_os = "linux", target_os = "macos")) {
             return self.absolute_path().and_then(|p| all_mounts().get(p));
             return self.absolute_path().and_then(|p| all_mounts().get(p));
         }
         }
         None
         None
@@ -285,14 +325,11 @@ impl<'dir> File<'dir> {
     fn reorient_target_path(&self, path: &Path) -> PathBuf {
     fn reorient_target_path(&self, path: &Path) -> PathBuf {
         if path.is_absolute() {
         if path.is_absolute() {
             path.to_path_buf()
             path.to_path_buf()
-        }
-        else if let Some(dir) = self.parent_dir {
+        } else if let Some(dir) = self.parent_dir {
             dir.join(path)
             dir.join(path)
-        }
-        else if let Some(parent) = self.path.parent() {
+        } else if let Some(parent) = self.path.parent() {
             parent.join(path)
             parent.join(path)
-        }
-        else {
+        } else {
             self.path.join(path)
             self.path.join(path)
         }
         }
     }
     }
@@ -308,15 +345,14 @@ impl<'dir> File<'dir> {
     /// existed. If this file cannot be read at all, returns the error that
     /// existed. If this file cannot be read at all, returns the error that
     /// we got when we tried to read it.
     /// we got when we tried to read it.
     pub fn link_target(&self) -> FileTarget<'dir> {
     pub fn link_target(&self) -> FileTarget<'dir> {
-
         // We need to be careful to treat the path actually pointed to by
         // We need to be careful to treat the path actually pointed to by
         // this file — which could be absolute or relative — to the path
         // this file — which could be absolute or relative — to the path
         // we actually look up and turn into a `File` — which needs to be
         // we actually look up and turn into a `File` — which needs to be
         // absolute to be accessible from any directory.
         // absolute to be accessible from any directory.
         debug!("Reading link {:?}", &self.path);
         debug!("Reading link {:?}", &self.path);
         let path = match std::fs::read_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);
         let absolute_path = self.reorient_target_path(&path);
@@ -325,7 +361,7 @@ impl<'dir> File<'dir> {
         // follow links.
         // follow links.
         match std::fs::metadata(&absolute_path) {
         match std::fs::metadata(&absolute_path) {
             Ok(metadata) => {
             Ok(metadata) => {
-                let ext  = File::ext(&path);
+                let ext = File::ext(&path);
                 let name = File::filename(&path);
                 let name = File::filename(&path);
                 let extended_attributes = OnceLock::new();
                 let extended_attributes = OnceLock::new();
                 let absolute_path_cell = OnceLock::from(Some(absolute_path));
                 let absolute_path_cell = OnceLock::from(Some(absolute_path));
@@ -401,8 +437,7 @@ impl<'dir> File<'dir> {
             // for 512 byte blocks according to the POSIX standard
             // for 512 byte blocks according to the POSIX standard
             // even though the physical block size may be different.
             // even though the physical block size may be different.
             f::Blocksize::Some(self.metadata.blocks() * 512)
             f::Blocksize::Some(self.metadata.blocks() * 512)
-        }
-        else {
+        } else {
             f::Blocksize::None
             f::Blocksize::None
         }
         }
     }
     }
@@ -413,8 +448,8 @@ impl<'dir> File<'dir> {
     pub fn user(&self) -> Option<f::User> {
     pub fn user(&self) -> Option<f::User> {
         if self.is_link() && self.deref_links {
         if self.is_link() && self.deref_links {
             match self.link_target_recurse() {
             match self.link_target_recurse() {
-               FileTarget::Ok(f) => return f.user(),
-               _ => return None,
+                FileTarget::Ok(f) => return f.user(),
+                _ => return None,
             }
             }
         }
         }
         Some(f::User(self.metadata.uid()))
         Some(f::User(self.metadata.uid()))
@@ -425,8 +460,8 @@ impl<'dir> File<'dir> {
     pub fn group(&self) -> Option<f::Group> {
     pub fn group(&self) -> Option<f::Group> {
         if self.is_link() && self.deref_links {
         if self.is_link() && self.deref_links {
             match self.link_target_recurse() {
             match self.link_target_recurse() {
-               FileTarget::Ok(f) => return f.group(),
-               _ => return None,
+                FileTarget::Ok(f) => return f.group(),
+                _ => return None,
             }
             }
         }
         }
         Some(f::Group(self.metadata.gid()))
         Some(f::Group(self.metadata.gid()))
@@ -454,8 +489,7 @@ impl<'dir> File<'dir> {
         }
         }
         if self.is_directory() {
         if self.is_directory() {
             f::Size::None
             f::Size::None
-        }
-        else if self.is_char_device() || self.is_block_device() {
+        } else if self.is_char_device() || self.is_block_device() {
             let device_id = self.metadata.rdev();
             let device_id = self.metadata.rdev();
 
 
             // MacOS and Linux have different arguments and return types for the
             // MacOS and Linux have different arguments and return types for the
@@ -470,11 +504,10 @@ impl<'dir> File<'dir> {
                 major: unsafe { libc::major(device_id.try_into().unwrap()) } as u32,
                 major: unsafe { libc::major(device_id.try_into().unwrap()) } as u32,
                 minor: unsafe { libc::minor(device_id.try_into().unwrap()) } as u32,
                 minor: unsafe { libc::minor(device_id.try_into().unwrap()) } as u32,
             })
             })
-        }
-        else if self.is_link() && self.deref_links {
+        } else if self.is_link() && self.deref_links {
             match self.link_target() {
             match self.link_target() {
                 FileTarget::Ok(f) => f.size(),
                 FileTarget::Ok(f) => f.size(),
-                _ => f::Size::None
+                _ => f::Size::None,
             }
             }
         } else {
         } else {
             f::Size::Some(self.metadata.len())
             f::Size::Some(self.metadata.len())
@@ -483,21 +516,20 @@ impl<'dir> File<'dir> {
 
 
     /// Returns the size of the file or indicates no size if it's a directory.
     /// Returns the size of the file or indicates no size if it's a directory.
     ///
     ///
-    /// For Windows platforms, the size of directories is not computed and will 
+    /// For Windows platforms, the size of directories is not computed and will
     /// return `Size::None`.
     /// return `Size::None`.
     #[cfg(windows)]
     #[cfg(windows)]
     pub fn size(&self) -> f::Size {
     pub fn size(&self) -> f::Size {
         if self.is_directory() {
         if self.is_directory() {
             f::Size::None
             f::Size::None
-        }
-        else {
+        } else {
             f::Size::Some(self.metadata.len())
             f::Size::Some(self.metadata.len())
         }
         }
     }
     }
 
 
     /// Determines if the directory is empty or not.
     /// Determines if the directory is empty or not.
     ///
     ///
-    /// For Unix platforms, this function first checks the link count to quickly 
+    /// For Unix platforms, this function first checks the link count to quickly
     /// determine non-empty directories. On most UNIX filesystems the link count
     /// determine non-empty directories. On most UNIX filesystems the link count
     /// is two plus the number of subdirectories. If the link count is less than
     /// is two plus the number of subdirectories. If the link count is less than
     /// or equal to 2, it then checks the directory contents to determine if
     /// or equal to 2, it then checks the directory contents to determine if
@@ -524,8 +556,8 @@ impl<'dir> File<'dir> {
 
 
     /// Determines if the directory is empty or not.
     /// Determines if the directory is empty or not.
     ///
     ///
-    /// For Windows platforms, this function checks the directory contents directly 
-    /// to determine if it's empty. Since certain filesystems on Windows make it 
+    /// For Windows platforms, this function checks the directory contents directly
+    /// to determine if it's empty. Since certain filesystems on Windows make it
     /// challenging to infer emptiness based on directory size, this approach is used.
     /// challenging to infer emptiness based on directory size, this approach is used.
     #[cfg(windows)]
     #[cfg(windows)]
     pub fn is_empty_dir(&self) -> bool {
     pub fn is_empty_dir(&self) -> bool {
@@ -538,7 +570,7 @@ impl<'dir> File<'dir> {
 
 
     /// Checks the contents of the directory to determine if it's empty.
     /// Checks the contents of the directory to determine if it's empty.
     ///
     ///
-    /// This function avoids counting '.' and '..' when determining if the directory is 
+    /// This function avoids counting '.' and '..' when determining if the directory is
     /// empty. If any other entries are found, it returns `false`.
     /// empty. If any other entries are found, it returns `false`.
     ///
     ///
     /// The naive approach, as one would think that this info may have been cached.
     /// The naive approach, as one would think that this info may have been cached.
@@ -548,7 +580,10 @@ impl<'dir> File<'dir> {
         trace!("is_empty_directory: reading dir");
         trace!("is_empty_directory: reading dir");
         match Dir::read_dir(self.path.clone()) {
         match Dir::read_dir(self.path.clone()) {
             // . & .. are skipped, if the returned iterator has .next(), it's not empty
             // . & .. are skipped, if the returned iterator has .next(), it's not empty
-            Ok(has_files) => has_files.files(super::DotFilter::Dotfiles, None, false, false).next().is_none(),
+            Ok(has_files) => has_files
+                .files(super::DotFilter::Dotfiles, None, false, false)
+                .next()
+                .is_none(),
             Err(_) => false,
             Err(_) => false,
         }
         }
     }
     }
@@ -558,10 +593,13 @@ impl<'dir> File<'dir> {
         if self.is_link() && self.deref_links {
         if self.is_link() && self.deref_links {
             return match self.link_target_recurse() {
             return match self.link_target_recurse() {
                 FileTarget::Ok(f) => f.modified_time(),
                 FileTarget::Ok(f) => f.modified_time(),
-                _ => None, 
+                _ => None,
             };
             };
         }
         }
-        self.metadata.modified().map(|st| DateTime::<Utc>::from(st).naive_utc()).ok()
+        self.metadata
+            .modified()
+            .map(|st| DateTime::<Utc>::from(st).naive_utc())
+            .ok()
     }
     }
 
 
     /// This file’s last changed timestamp, if available on this platform.
     /// This file’s last changed timestamp, if available on this platform.
@@ -573,10 +611,7 @@ impl<'dir> File<'dir> {
                 _ => None,
                 _ => None,
             };
             };
         }
         }
-        NaiveDateTime::from_timestamp_opt(
-            self.metadata.ctime(),
-            self.metadata.ctime_nsec() as u32,
-        )
+        NaiveDateTime::from_timestamp_opt(self.metadata.ctime(), self.metadata.ctime_nsec() as u32)
     }
     }
 
 
     #[cfg(windows)]
     #[cfg(windows)]
@@ -589,10 +624,13 @@ impl<'dir> File<'dir> {
         if self.is_link() && self.deref_links {
         if self.is_link() && self.deref_links {
             return match self.link_target_recurse() {
             return match self.link_target_recurse() {
                 FileTarget::Ok(f) => f.accessed_time(),
                 FileTarget::Ok(f) => f.accessed_time(),
-                _ => None, 
+                _ => None,
             };
             };
         }
         }
-        self.metadata.accessed().map(|st| DateTime::<Utc>::from(st).naive_utc()).ok()
+        self.metadata
+            .accessed()
+            .map(|st| DateTime::<Utc>::from(st).naive_utc())
+            .ok()
     }
     }
 
 
     /// This file’s created timestamp, if available on this platform.
     /// This file’s created timestamp, if available on this platform.
@@ -603,7 +641,10 @@ impl<'dir> File<'dir> {
                 _ => None,
                 _ => None,
             };
             };
         }
         }
-        self.metadata.created().map(|st| DateTime::<Utc>::from(st).naive_utc()).ok()
+        self.metadata
+            .created()
+            .map(|st| DateTime::<Utc>::from(st).naive_utc())
+            .ok()
     }
     }
 
 
     /// This file’s ‘type’.
     /// This file’s ‘type’.
@@ -615,26 +656,19 @@ impl<'dir> File<'dir> {
     pub fn type_char(&self) -> f::Type {
     pub fn type_char(&self) -> f::Type {
         if self.is_file() {
         if self.is_file() {
             f::Type::File
             f::Type::File
-        }
-        else if self.is_directory() {
+        } else if self.is_directory() {
             f::Type::Directory
             f::Type::Directory
-        }
-        else if self.is_pipe() {
+        } else if self.is_pipe() {
             f::Type::Pipe
             f::Type::Pipe
-        }
-        else if self.is_link() {
+        } else if self.is_link() {
             f::Type::Link
             f::Type::Link
-        }
-        else if self.is_char_device() {
+        } else if self.is_char_device() {
             f::Type::CharDevice
             f::Type::CharDevice
-        }
-        else if self.is_block_device() {
+        } else if self.is_block_device() {
             f::Type::BlockDevice
             f::Type::BlockDevice
-        }
-        else if self.is_socket() {
+        } else if self.is_socket() {
             f::Type::Socket
             f::Type::Socket
-        }
-        else {
+        } else {
             f::Type::Special
             f::Type::Special
         }
         }
     }
     }
@@ -643,11 +677,9 @@ impl<'dir> File<'dir> {
     pub fn type_char(&self) -> f::Type {
     pub fn type_char(&self) -> f::Type {
         if self.is_file() {
         if self.is_file() {
             f::Type::File
             f::Type::File
-        }
-        else if self.is_directory() {
+        } else if self.is_directory() {
             f::Type::Directory
             f::Type::Directory
-        }
-        else {
+        } else {
             f::Type::Special
             f::Type::Special
         }
         }
     }
     }
@@ -660,29 +692,29 @@ impl<'dir> File<'dir> {
             // return the permissions of the original link, as would have been
             // return the permissions of the original link, as would have been
             // done if we were not dereferencing.
             // done if we were not dereferencing.
             match self.link_target_recurse() {
             match self.link_target_recurse() {
-                FileTarget::Ok(f)   => return f.permissions(),
-                _                   => return None,
+                FileTarget::Ok(f) => return f.permissions(),
+                _ => return None,
             }
             }
         }
         }
         let bits = self.metadata.mode();
         let bits = self.metadata.mode();
         let has_bit = |bit| bits & bit == bit;
         let has_bit = |bit| bits & bit == bit;
 
 
         Some(f::Permissions {
         Some(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),
         })
         })
     }
     }
 
 
@@ -693,37 +725,38 @@ impl<'dir> File<'dir> {
 
 
         // https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
         // https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
         f::Attributes {
         f::Attributes {
-            directory:      has_bit(0x10),
-            archive:        has_bit(0x20),
-            readonly:       has_bit(0x1),
-            hidden:         has_bit(0x2),
-            system:         has_bit(0x4),
-            reparse_point:  has_bit(0x400),
+            directory: has_bit(0x10),
+            archive: has_bit(0x20),
+            readonly: has_bit(0x1),
+            hidden: has_bit(0x2),
+            system: has_bit(0x4),
+            reparse_point: has_bit(0x400),
         }
         }
     }
     }
 
 
     /// This file’s security context field.
     /// This file’s security context field.
     pub fn security_context(&self) -> f::SecurityContext<'_> {
     pub fn security_context(&self) -> f::SecurityContext<'_> {
-        let context = match self.extended_attributes().iter().find(|a| a.name == "security.selinux") {
+        let context = match self
+            .extended_attributes()
+            .iter()
+            .find(|a| a.name == "security.selinux")
+        {
             Some(attr) => f::SecurityContextType::SELinux(&attr.value),
             Some(attr) => f::SecurityContextType::SELinux(&attr.value),
-            None       => f::SecurityContextType::None
+            None => f::SecurityContextType::None,
         };
         };
 
 
         f::SecurityContext { context }
         f::SecurityContext { context }
     }
     }
 }
 }
 
 
-
 impl<'a> AsRef<File<'a>> for File<'a> {
 impl<'a> AsRef<File<'a>> for File<'a> {
     fn as_ref(&self) -> &File<'a> {
     fn as_ref(&self) -> &File<'a> {
         self
         self
     }
     }
 }
 }
 
 
-
 /// The result of following a symlink.
 /// The result of following a symlink.
 pub enum FileTarget<'dir> {
 pub enum FileTarget<'dir> {
-
     /// The symlink pointed at a file that exists.
     /// The symlink pointed at a file that exists.
     Ok(Box<File<'dir>>),
     Ok(Box<File<'dir>>),
 
 
@@ -735,14 +768,12 @@ pub enum FileTarget<'dir> {
     /// file isn’t a link to begin with, but also if, say, we don’t have
     /// file isn’t a link to begin with, but also if, say, we don’t have
     /// permission to follow it.
     /// permission to follow it.
     Err(io::Error),
     Err(io::Error),
-
     // Err is its own variant, instead of having the whole thing be inside an
     // Err is its own variant, instead of having the whole thing be inside an
     // `io::Result`, because being unable to follow a symlink is not a serious
     // `io::Result`, because being unable to follow a symlink is not a serious
     // error — we just display the error message and move on.
     // error — we just display the error message and move on.
 }
 }
 
 
 impl<'dir> FileTarget<'dir> {
 impl<'dir> FileTarget<'dir> {
-
     /// Whether this link doesn’t lead to a file, for whatever reason. This
     /// 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.
     /// gets used to determine how to highlight the link in grid views.
     pub fn is_broken(&self) -> bool {
     pub fn is_broken(&self) -> bool {
@@ -750,7 +781,6 @@ impl<'dir> FileTarget<'dir> {
     }
     }
 }
 }
 
 
-
 /// More readable aliases for the permission bits exposed by libc.
 /// More readable aliases for the permission bits exposed by libc.
 #[allow(trivial_numeric_casts)]
 #[allow(trivial_numeric_casts)]
 #[cfg(unix)]
 #[cfg(unix)]
@@ -760,24 +790,23 @@ mod modes {
     // from `metadata.permissions().mode()` is always `u32`.
     // from `metadata.permissions().mode()` is always `u32`.
     pub type Mode = 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 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 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)]
 #[cfg(test)]
 mod ext_test {
 mod ext_test {
     use super::File;
     use super::File;
@@ -799,7 +828,6 @@ mod ext_test {
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod filename_test {
 mod filename_test {
     use super::File;
     use super::File;

+ 31 - 40
src/fs/filter.rs

@@ -8,8 +8,6 @@ use std::os::unix::fs::MetadataExt;
 use crate::fs::DotFilter;
 use crate::fs::DotFilter;
 use crate::fs::File;
 use crate::fs::File;
 
 
-
-
 /// Flags used to manage the **file filter** process
 /// Flags used to manage the **file filter** process
 #[derive(PartialEq, Eq, Debug, Clone)]
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub enum FileFilterFlags {
 pub enum FileFilterFlags {
@@ -22,10 +20,9 @@ pub enum FileFilterFlags {
     OnlyDirs,
     OnlyDirs,
 
 
     /// Whether to only show files.
     /// Whether to only show files.
-    OnlyFiles
+    OnlyFiles,
 }
 }
 
 
-
 /// The **file filter** processes a list of files before displaying them to
 /// The **file filter** processes a list of files before displaying them to
 /// the user, by removing files they don’t want to see, and putting the list
 /// the user, by removing files they don’t want to see, and putting the list
 /// in the desired order.
 /// in the desired order.
@@ -42,7 +39,6 @@ pub enum FileFilterFlags {
 /// performing the comparison.
 /// performing the comparison.
 #[derive(PartialEq, Eq, Debug, Clone)]
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct FileFilter {
 pub struct FileFilter {
-
     /// Whether directories should be listed first, and other types of file
     /// Whether directories should be listed first, and other types of file
     /// second. Some users prefer it like this.
     /// second. Some users prefer it like this.
     pub list_dirs_first: bool,
     pub list_dirs_first: bool,
@@ -79,10 +75,13 @@ impl FileFilter {
     /// filter predicate for files found inside a directory.
     /// filter predicate for files found inside a directory.
     pub fn filter_child_files(&self, files: &mut Vec<File<'_>>) {
     pub fn filter_child_files(&self, files: &mut Vec<File<'_>>) {
         use FileFilterFlags::{OnlyDirs, OnlyFiles};
         use FileFilterFlags::{OnlyDirs, OnlyFiles};
-        
-        files.retain(|f| ! self.ignore_patterns.is_ignored(&f.name));
 
 
-        match (self.flags.contains(&OnlyDirs), self.flags.contains(&OnlyFiles)) {
+        files.retain(|f| !self.ignore_patterns.is_ignored(&f.name));
+
+        match (
+            self.flags.contains(&OnlyDirs),
+            self.flags.contains(&OnlyFiles),
+        ) {
             (true, false) => {
             (true, false) => {
                 // On pass -'-only-dirs' flag only
                 // On pass -'-only-dirs' flag only
                 files.retain(File::is_directory);
                 files.retain(File::is_directory);
@@ -93,7 +92,6 @@ impl FileFilter {
             }
             }
             _ => {}
             _ => {}
         }
         }
-       
     }
     }
 
 
     /// Remove every file in the given vector that does *not* pass the
     /// Remove every file in the given vector that does *not* pass the
@@ -106,18 +104,15 @@ impl FileFilter {
     /// `exa -I='*.ogg' music/*` should filter out the ogg files obtained
     /// `exa -I='*.ogg' music/*` should filter out the ogg files obtained
     /// from the glob, even though the globbing is done by the shell!
     /// from the glob, even though the globbing is done by the shell!
     pub fn filter_argument_files(&self, files: &mut Vec<File<'_>>) {
     pub fn filter_argument_files(&self, files: &mut Vec<File<'_>>) {
-        files.retain(|f| {
-            ! self.ignore_patterns.is_ignored(&f.name)
-        });
+        files.retain(|f| !self.ignore_patterns.is_ignored(&f.name));
     }
     }
 
 
     /// Sort the files in the given vector based on the sort field option.
     /// Sort the files in the given vector based on the sort field option.
     pub fn sort_files<'a, F>(&self, files: &mut [F])
     pub fn sort_files<'a, F>(&self, files: &mut [F])
-    where F: AsRef<File<'a>>
+    where
+        F: AsRef<File<'a>>,
     {
     {
-        files.sort_by(|a, b| {
-            self.sort_field.compare_files(a.as_ref(), b.as_ref())
-        });
+        files.sort_by(|a, b| self.sort_field.compare_files(a.as_ref(), b.as_ref()));
 
 
         if self.flags.contains(&FileFilterFlags::Reverse) {
         if self.flags.contains(&FileFilterFlags::Reverse) {
             files.reverse();
             files.reverse();
@@ -127,18 +122,17 @@ impl FileFilter {
             // This relies on the fact that `sort_by` is *stable*: it will keep
             // This relies on the fact that `sort_by` is *stable*: it will keep
             // adjacent elements next to each other.
             // adjacent elements next to each other.
             files.sort_by(|a, b| {
             files.sort_by(|a, b| {
-                b.as_ref().points_to_directory()
+                b.as_ref()
+                    .points_to_directory()
                     .cmp(&a.as_ref().points_to_directory())
                     .cmp(&a.as_ref().points_to_directory())
             });
             });
         }
         }
     }
     }
 }
 }
 
 
-
 /// User-supplied field to sort by.
 /// User-supplied field to sort by.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum SortField {
 pub enum SortField {
-
     /// Don’t apply any sorting. This is usually used as an optimisation in
     /// Don’t apply any sorting. This is usually used as an optimisation in
     /// scripts, where the order doesn’t matter.
     /// scripts, where the order doesn’t matter.
     Unsorted,
     Unsorted,
@@ -219,7 +213,6 @@ pub enum SortField {
 /// effects they have.
 /// effects they have.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum SortCase {
 pub enum SortCase {
-
     /// Sort files case-sensitively with uppercase first, with ‘A’ coming
     /// Sort files case-sensitively with uppercase first, with ‘A’ coming
     /// before ‘a’.
     /// before ‘a’.
     ABCabc,
     ABCabc,
@@ -229,7 +222,6 @@ pub enum SortCase {
 }
 }
 
 
 impl SortField {
 impl SortField {
-
     /// Compares two files to determine the order they should be listed in,
     /// Compares two files to determine the order they should be listed in,
     /// depending on the search field.
     /// depending on the search field.
     ///
     ///
@@ -241,7 +233,8 @@ impl SortField {
     pub fn compare_files(self, a: &File<'_>, b: &File<'_>) -> Ordering {
     pub fn compare_files(self, a: &File<'_>, b: &File<'_>) -> Ordering {
         use self::SortCase::{ABCabc, AaBbCc};
         use self::SortCase::{ABCabc, AaBbCc};
 
 
-        match self {
+        #[rustfmt::skip]
+        return match self {
             Self::Unsorted  => Ordering::Equal,
             Self::Unsorted  => Ordering::Equal,
 
 
             Self::Name(ABCabc)  => natord::compare(&a.name, &b.name),
             Self::Name(ABCabc)  => natord::compare(&a.name, &b.name),
@@ -279,18 +272,17 @@ impl SortField {
                 Self::strip_dot(&a.name),
                 Self::strip_dot(&a.name),
                 Self::strip_dot(&b.name)
                 Self::strip_dot(&b.name)
             )
             )
-        }
+        };
     }
     }
 
 
     fn strip_dot(n: &str) -> &str {
     fn strip_dot(n: &str) -> &str {
         match n.strip_prefix('.') {
         match n.strip_prefix('.') {
             Some(s) => s,
             Some(s) => s,
-            None    => n,
+            None => n,
         }
         }
     }
     }
 }
 }
 
 
-
 /// The **ignore patterns** are a list of globs that are tested against
 /// 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.
 /// each filename, and if any of them match, that file isn’t displayed.
 /// This lets a user hide, say, text files by ignoring `*.txt`.
 /// This lets a user hide, say, text files by ignoring `*.txt`.
@@ -300,9 +292,9 @@ pub struct IgnorePatterns {
 }
 }
 
 
 impl FromIterator<glob::Pattern> for IgnorePatterns {
 impl FromIterator<glob::Pattern> for IgnorePatterns {
-
     fn from_iter<I>(iter: I) -> Self
     fn from_iter<I>(iter: I) -> Self
-    where I: IntoIterator<Item = glob::Pattern>
+    where
+        I: IntoIterator<Item = glob::Pattern>,
     {
     {
         let patterns = iter.into_iter().collect();
         let patterns = iter.into_iter().collect();
         Self { patterns }
         Self { patterns }
@@ -310,18 +302,19 @@ impl FromIterator<glob::Pattern> for IgnorePatterns {
 }
 }
 
 
 impl IgnorePatterns {
 impl IgnorePatterns {
-
     /// Create a new list from the input glob strings, turning the inputs that
     /// Create a new list from the input glob strings, turning the inputs that
     /// are valid glob patterns into an `IgnorePatterns`. The inputs that
     /// are valid glob patterns into an `IgnorePatterns`. The inputs that
     /// don’t parse correctly are returned separately.
     /// don’t parse correctly are returned separately.
-    pub fn parse_from_iter<'a, I: IntoIterator<Item = &'a str>>(iter: I) -> (Self, Vec<glob::PatternError>) {
+    pub fn parse_from_iter<'a, I: IntoIterator<Item = &'a str>>(
+        iter: I,
+    ) -> (Self, Vec<glob::PatternError>) {
         let iter = iter.into_iter();
         let iter = iter.into_iter();
 
 
         // Almost all glob patterns are valid, so it’s worth pre-allocating
         // Almost all glob patterns are valid, so it’s worth pre-allocating
         // the vector with enough space for all of them.
         // the vector with enough space for all of them.
         let mut patterns = match iter.size_hint() {
         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.
         // Similarly, assume there won’t be any errors.
@@ -330,7 +323,7 @@ impl IgnorePatterns {
         for input in iter {
         for input in iter {
             match glob::Pattern::new(input) {
             match glob::Pattern::new(input) {
                 Ok(pat) => patterns.push(pat),
                 Ok(pat) => patterns.push(pat),
-                Err(e)  => errors.push(e),
+                Err(e) => errors.push(e),
             }
             }
         }
         }
 
 
@@ -339,7 +332,9 @@ impl IgnorePatterns {
 
 
     /// Create a new empty set of patterns that matches nothing.
     /// Create a new empty set of patterns that matches nothing.
     pub fn empty() -> Self {
     pub fn empty() -> Self {
-        Self { patterns: Vec::new() }
+        Self {
+            patterns: Vec::new(),
+        }
     }
     }
 
 
     /// Test whether the given file should be hidden from the results.
     /// Test whether the given file should be hidden from the results.
@@ -348,11 +343,9 @@ impl IgnorePatterns {
     }
     }
 }
 }
 
 
-
 /// Whether to ignore or display files that Git would ignore.
 /// Whether to ignore or display files that Git would ignore.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum GitIgnore {
 pub enum GitIgnore {
-
     /// Ignore files that Git would ignore.
     /// Ignore files that Git would ignore.
     CheckAndIgnore,
     CheckAndIgnore,
 
 
@@ -360,8 +353,6 @@ pub enum GitIgnore {
     Off,
     Off,
 }
 }
 
 
-
-
 #[cfg(test)]
 #[cfg(test)]
 mod test_ignores {
 mod test_ignores {
     use super::*;
     use super::*;
@@ -375,7 +366,7 @@ mod test_ignores {
 
 
     #[test]
     #[test]
     fn ignores_a_glob() {
     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!(fails.is_empty());
         assert!(!pats.is_ignored("nothing"));
         assert!(!pats.is_ignored("nothing"));
         assert!(pats.is_ignored("test.mp3"));
         assert!(pats.is_ignored("test.mp3"));
@@ -383,7 +374,7 @@ mod test_ignores {
 
 
     #[test]
     #[test]
     fn ignores_an_exact_filename() {
     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!(fails.is_empty());
         assert!(pats.is_ignored("nothing"));
         assert!(pats.is_ignored("nothing"));
         assert!(!pats.is_ignored("test.mp3"));
         assert!(!pats.is_ignored("test.mp3"));
@@ -391,7 +382,7 @@ mod test_ignores {
 
 
     #[test]
     #[test]
     fn ignores_both() {
     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!(fails.is_empty());
         assert!(pats.is_ignored("nothing"));
         assert!(pats.is_ignored("nothing"));
         assert!(pats.is_ignored("test.mp3"));
         assert!(pats.is_ignored("test.mp3"));

+ 11 - 11
src/fs/mounts/linux.rs

@@ -1,16 +1,16 @@
-use proc_mounts::MountList;
 use crate::fs::mounts::{Error, MountedFs};
 use crate::fs::mounts::{Error, MountedFs};
+use proc_mounts::MountList;
 
 
 /// Get a list of all mounted filesystems
 /// Get a list of all mounted filesystems
 pub fn mounts() -> Result<Vec<MountedFs>, Error> {
 pub fn mounts() -> Result<Vec<MountedFs>, Error> {
     Ok(MountList::new()
     Ok(MountList::new()
-           .map_err(Error::IOError)?
-           .0.iter()
-           .map(|mount| MountedFs {
-               dest: mount.dest.clone(),
-               fstype: mount.fstype.clone(),
-               source: mount.source.to_string_lossy().into()
-           })
-           .collect()
-    )
-}
+        .map_err(Error::IOError)?
+        .0
+        .iter()
+        .map(|mount| MountedFs {
+            dest: mount.dest.clone(),
+            fstype: mount.fstype.clone(),
+            source: mount.source.to_string_lossy().into(),
+        })
+        .collect())
+}

+ 10 - 6
src/fs/mounts/macos.rs

@@ -1,10 +1,10 @@
-use std::{mem, ptr};
+use crate::fs::mounts::{Error, MountedFs};
+use libc::{__error, getfsstat, statfs, MNT_NOWAIT};
 use std::ffi::{CStr, OsStr};
 use std::ffi::{CStr, OsStr};
 use std::os::raw::{c_char, c_int};
 use std::os::raw::{c_char, c_int};
 use std::os::unix::ffi::OsStrExt;
 use std::os::unix::ffi::OsStrExt;
 use std::path::PathBuf;
 use std::path::PathBuf;
-use libc::{__error, getfsstat, MNT_NOWAIT, statfs};
-use crate::fs::mounts::{Error, MountedFs};
+use std::{mem, ptr};
 
 
 /// Get a list of all mounted filesystem
 /// Get a list of all mounted filesystem
 pub fn mounts() -> Result<Vec<MountedFs>, Error> {
 pub fn mounts() -> Result<Vec<MountedFs>, Error> {
@@ -36,7 +36,7 @@ pub fn mounts() -> Result<Vec<MountedFs>, Error> {
     for mnt in &mntbuf {
     for mnt in &mntbuf {
         let mount_point = OsStr::from_bytes(
         let mount_point = OsStr::from_bytes(
             // SAFETY: Converting null terminated "C" string
             // SAFETY: Converting null terminated "C" string
-            unsafe { CStr::from_ptr(mnt.f_mntonname.as_ptr().cast::<c_char>()) }.to_bytes()
+            unsafe { CStr::from_ptr(mnt.f_mntonname.as_ptr().cast::<c_char>()) }.to_bytes(),
         );
         );
         let dest = PathBuf::from(mount_point);
         let dest = PathBuf::from(mount_point);
         // SAFETY: Converting null terminated "C" string
         // SAFETY: Converting null terminated "C" string
@@ -47,8 +47,12 @@ pub fn mounts() -> Result<Vec<MountedFs>, Error> {
         let source = unsafe { CStr::from_ptr(mnt.f_mntfromname.as_ptr().cast::<c_char>()) }
         let source = unsafe { CStr::from_ptr(mnt.f_mntfromname.as_ptr().cast::<c_char>()) }
             .to_string_lossy()
             .to_string_lossy()
             .into();
             .into();
-        mounts.push(MountedFs { dest, fstype, source });
+        mounts.push(MountedFs {
+            dest,
+            fstype,
+            source,
+        });
     }
     }
 
 
     Ok(mounts)
     Ok(mounts)
-}
+}

+ 5 - 5
src/fs/mounts/mod.rs

@@ -26,7 +26,7 @@ pub enum Error {
     #[cfg(target_os = "macos")]
     #[cfg(target_os = "macos")]
     GetFSStatError(i32),
     GetFSStatError(i32),
     #[cfg(target_os = "linux")]
     #[cfg(target_os = "linux")]
-    IOError(std::io::Error)
+    IOError(std::io::Error),
 }
 }
 
 
 impl std::error::Error for Error {}
 impl std::error::Error for Error {}
@@ -39,8 +39,8 @@ impl std::fmt::Display for Error {
             #[cfg(target_os = "macos")]
             #[cfg(target_os = "macos")]
             Error::GetFSStatError(err) => write!(f, "getfsstat failed: {err}"),
             Error::GetFSStatError(err) => write!(f, "getfsstat failed: {err}"),
             #[cfg(target_os = "linux")]
             #[cfg(target_os = "linux")]
-            Error::IOError(err)        => write!(f, "failed to read /proc/mounts: {err}"),
-            _                          => write!(f, "Unknown error"),
+            Error::IOError(err) => write!(f, "failed to read /proc/mounts: {err}"),
+            _ => write!(f, "Unknown error"),
         }
         }
     }
     }
 }
 }
@@ -64,7 +64,7 @@ pub(super) fn all_mounts() -> &'static HashMap<PathBuf, MountedFs> {
         let mut mount_map: HashMap<PathBuf, MountedFs> = HashMap::new();
         let mut mount_map: HashMap<PathBuf, MountedFs> = HashMap::new();
 
 
         #[cfg(any(target_os = "linux", target_os = "macos"))]
         #[cfg(any(target_os = "linux", target_os = "macos"))]
-        if let Ok(mounts)  = mounts() {
+        if let Ok(mounts) = mounts() {
             for mount in mounts {
             for mount in mounts {
                 mount_map.insert(mount.dest.clone(), mount);
                 mount_map.insert(mount.dest.clone(), mount);
             }
             }
@@ -72,4 +72,4 @@ pub(super) fn all_mounts() -> &'static HashMap<PathBuf, MountedFs> {
 
 
         mount_map
         mount_map
     })
     })
-}
+}

+ 13 - 9
src/info/filetype.rs

@@ -22,9 +22,9 @@ pub enum FileType {
     Compressed,
     Compressed,
     Temp,
     Temp,
     Compiled,
     Compiled,
-    Build     // A “build file is something that can be run or activated somehow in order to
-              // kick off the build of a project. It’s usually only present in directories full of
-              // source code.
+    Build, // A “build file is something that can be run or activated somehow in order to
+           // kick off the build of a project. It’s usually only present in directories full of
+           // source code.
 }
 }
 
 
 /// Mapping from full filenames to file type.
 /// Mapping from full filenames to file type.
@@ -270,20 +270,24 @@ impl FileType {
     pub(crate) fn get_file_type(file: &File<'_>) -> Option<FileType> {
     pub(crate) fn get_file_type(file: &File<'_>) -> Option<FileType> {
         // Case-insensitive readme is checked first for backwards compatibility.
         // Case-insensitive readme is checked first for backwards compatibility.
         if file.name.to_lowercase().starts_with("readme") {
         if file.name.to_lowercase().starts_with("readme") {
-            return Some(Self::Build)
+            return Some(Self::Build);
         }
         }
         if let Some(file_type) = FILENAME_TYPES.get(&file.name) {
         if let Some(file_type) = FILENAME_TYPES.get(&file.name) {
-            return Some(file_type.clone())
+            return Some(file_type.clone());
         }
         }
         if let Some(file_type) = file.ext.as_ref().and_then(|ext| EXTENSION_TYPES.get(ext)) {
         if let Some(file_type) = file.ext.as_ref().and_then(|ext| EXTENSION_TYPES.get(ext)) {
-            return Some(file_type.clone())
+            return Some(file_type.clone());
         }
         }
         if file.name.ends_with('~') || (file.name.starts_with('#') && file.name.ends_with('#')) {
         if file.name.ends_with('~') || (file.name.starts_with('#') && file.name.ends_with('#')) {
-            return Some(Self::Temp)
+            return Some(Self::Temp);
         }
         }
         if let Some(dir) = file.parent_dir {
         if let Some(dir) = file.parent_dir {
-            if file.get_source_files().iter().any(|path| dir.contains(path)) {
-                return Some(Self::Compiled)
+            if file
+                .get_source_files()
+                .iter()
+                .any(|path| dir.contains(path))
+            {
+                return Some(Self::Compiled);
             }
             }
         }
         }
         None
         None

+ 2 - 5
src/info/sources.rs

@@ -2,9 +2,7 @@ use std::path::PathBuf;
 
 
 use crate::fs::File;
 use crate::fs::File;
 
 
-
 impl<'a> File<'a> {
 impl<'a> File<'a> {
-
     /// For this file, return a vector of alternate file paths that, if any of
     /// For this file, return a vector of alternate file paths that, if any of
     /// them exist, mean that *this* file should be coloured as “compiled”.
     /// them exist, mean that *this* file should be coloured as “compiled”.
     ///
     ///
@@ -37,9 +35,8 @@ impl<'a> File<'a> {
 
 
                 _ => vec![],  // No source files if none of the above
                 _ => vec![],  // No source files if none of the above
             }
             }
-        }
-        else {
-            vec![]  // No source files if there’s no extension, either!
+        } else {
+            vec![] // No source files if there’s no extension, either!
         }
         }
     }
     }
 }
 }

+ 19 - 14
src/logger.rs

@@ -2,8 +2,7 @@
 
 
 use std::ffi::OsStr;
 use std::ffi::OsStr;
 
 
-use ansiterm::{Colour, ANSIString};
-
+use ansiterm::{ANSIString, Colour};
 
 
 /// Sets the internal logger, changing the log level based on the value of an
 /// Sets the internal logger, changing the log level based on the value of an
 /// environment variable.
 /// environment variable.
@@ -17,8 +16,7 @@ pub fn configure<T: AsRef<OsStr>>(ev: Option<T>) {
 
 
     if env_var == "trace" {
     if env_var == "trace" {
         log::set_max_level(log::LevelFilter::Trace);
         log::set_max_level(log::LevelFilter::Trace);
-    }
-    else {
+    } else {
         log::set_max_level(log::LevelFilter::Debug);
         log::set_max_level(log::LevelFilter::Debug);
     }
     }
 
 
@@ -28,7 +26,6 @@ pub fn configure<T: AsRef<OsStr>>(ev: Option<T>) {
     }
     }
 }
 }
 
 
-
 #[derive(Debug)]
 #[derive(Debug)]
 struct Logger;
 struct Logger;
 
 
@@ -36,7 +33,7 @@ const GLOBAL_LOGGER: &Logger = &Logger;
 
 
 impl log::Log for Logger {
 impl log::Log for Logger {
     fn enabled(&self, _: &log::Metadata<'_>) -> bool {
     fn enabled(&self, _: &log::Metadata<'_>) -> bool {
-        true  // no need to filter after using ‘set_max_level’.
+        true // no need to filter after using ‘set_max_level’.
     }
     }
 
 
     fn log(&self, record: &log::Record<'_>) {
     fn log(&self, record: &log::Record<'_>) {
@@ -44,7 +41,14 @@ impl log::Log for Logger {
         let level = level(record.level());
         let level = level(record.level());
         let close = Colour::Fixed(243).paint("]");
         let close = Colour::Fixed(243).paint("]");
 
 
-        eprintln!("{}{} {}{} {}", open, level, record.target(), close, record.args());
+        eprintln!(
+            "{}{} {}{} {}",
+            open,
+            level,
+            record.target(),
+            close,
+            record.args()
+        );
     }
     }
 
 
     fn flush(&self) {
     fn flush(&self) {
@@ -53,11 +57,12 @@ impl log::Log for Logger {
 }
 }
 
 
 fn level(level: log::Level) -> ANSIString<'static> {
 fn level(level: log::Level) -> ANSIString<'static> {
-    match level {
-        log::Level::Error  => Colour::Red.paint("ERROR"),
-        log::Level::Warn   => Colour::Yellow.paint("WARN"),
-        log::Level::Info   => Colour::Cyan.paint("INFO"),
-        log::Level::Debug  => Colour::Blue.paint("DEBUG"),
-        log::Level::Trace  => Colour::Fixed(245).paint("TRACE"),
-    }
+    #[rustfmt::skip]
+    return match level {
+        log::Level::Error => Colour::Red.paint("ERROR"),
+        log::Level::Warn  => Colour::Yellow.paint("WARN"),
+        log::Level::Info  => Colour::Cyan.paint("INFO"),
+        log::Level::Debug => Colour::Blue.paint("DEBUG"),
+        log::Level::Trace => Colour::Fixed(245).paint("TRACE"),
+    };
 }
 }

+ 124 - 48
src/main.rs

@@ -5,7 +5,6 @@
 #![warn(rust_2018_idioms)]
 #![warn(rust_2018_idioms)]
 #![warn(trivial_casts, trivial_numeric_casts)]
 #![warn(trivial_casts, trivial_numeric_casts)]
 #![warn(unused)]
 #![warn(unused)]
-
 #![warn(clippy::all, clippy::pedantic)]
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(clippy::cast_precision_loss)]
 #![allow(clippy::cast_precision_loss)]
 #![allow(clippy::cast_possible_truncation)]
 #![allow(clippy::cast_possible_truncation)]
@@ -24,7 +23,7 @@
 
 
 use std::env;
 use std::env;
 use std::ffi::{OsStr, OsString};
 use std::ffi::{OsStr, OsString};
-use std::io::{self, Write, ErrorKind};
+use std::io::{self, ErrorKind, Write};
 use std::path::{Component, PathBuf};
 use std::path::{Component, PathBuf};
 use std::process::exit;
 use std::process::exit;
 
 
@@ -32,11 +31,11 @@ use ansiterm::{ANSIStrings, Style};
 
 
 use log::*;
 use log::*;
 
 
-use crate::fs::{Dir, File};
 use crate::fs::feature::git::GitCache;
 use crate::fs::feature::git::GitCache;
 use crate::fs::filter::GitIgnore;
 use crate::fs::filter::GitIgnore;
-use crate::options::{Options, Vars, vars, OptionsResult};
-use crate::output::{escape, lines, grid, grid_details, details, View, Mode};
+use crate::fs::{Dir, File};
+use crate::options::{vars, Options, OptionsResult, Vars};
+use crate::output::{details, escape, grid, grid_details, lines, Mode, View};
 use crate::theme::Theme;
 use crate::theme::Theme;
 
 
 mod fs;
 mod fs;
@@ -62,20 +61,27 @@ fn main() {
     let args: Vec<_> = env::args_os().skip(1).collect();
     let args: Vec<_> = env::args_os().skip(1).collect();
     match Options::parse(args.iter().map(std::convert::AsRef::as_ref), &LiveVars) {
     match Options::parse(args.iter().map(std::convert::AsRef::as_ref), &LiveVars) {
         OptionsResult::Ok(options, mut input_paths) => {
         OptionsResult::Ok(options, mut input_paths) => {
-
             // List the current directory by default.
             // List the current directory by default.
             // (This has to be done here, otherwise git_options won’t see it.)
             // (This has to be done here, otherwise git_options won’t see it.)
             if input_paths.is_empty() {
             if input_paths.is_empty() {
-                input_paths = vec![ OsStr::new(".") ];
+                input_paths = vec![OsStr::new(".")];
             }
             }
 
 
             let git = git_options(&options, &input_paths);
             let git = git_options(&options, &input_paths);
             let writer = io::stdout();
             let writer = io::stdout();
 
 
             let console_width = options.view.width.actual_terminal_width();
             let console_width = options.view.width.actual_terminal_width();
-            let theme = options.theme.to_theme(terminal_size::terminal_size().is_some());
-            let exa = Exa { options, writer, input_paths, theme, console_width, git };
-
+            let theme = options
+                .theme
+                .to_theme(terminal_size::terminal_size().is_some());
+            let exa = Exa {
+                options,
+                writer,
+                input_paths,
+                theme,
+                console_width,
+                git,
+            };
 
 
             info!("matching on exa.run");
             info!("matching on exa.run");
             match exa.run() {
             match exa.run() {
@@ -117,10 +123,8 @@ fn main() {
     }
     }
 }
 }
 
 
-
 /// The main program wrapper.
 /// The main program wrapper.
 pub struct Exa<'args> {
 pub struct Exa<'args> {
-
     /// List of command-line options, having been successfully parsed.
     /// List of command-line options, having been successfully parsed.
     pub options: Options,
     pub options: Options,
 
 
@@ -161,8 +165,7 @@ impl Vars for LiveVars {
 fn git_options(options: &Options, args: &[&OsStr]) -> Option<GitCache> {
 fn git_options(options: &Options, args: &[&OsStr]) -> Option<GitCache> {
     if options.should_scan_for_git() {
     if options.should_scan_for_git() {
         Some(args.iter().map(PathBuf::from).collect())
         Some(args.iter().map(PathBuf::from).collect())
-    }
-    else {
+    } else {
         None
         None
     }
     }
 }
 }
@@ -179,25 +182,29 @@ impl<'args> Exa<'args> {
         let mut exit_status = 0;
         let mut exit_status = 0;
 
 
         for file_path in &self.input_paths {
         for file_path in &self.input_paths {
-            match File::from_args(PathBuf::from(file_path), None, None, self.options.view.deref_links) {
+            match File::from_args(
+                PathBuf::from(file_path),
+                None,
+                None,
+                self.options.view.deref_links,
+            ) {
                 Err(e) => {
                 Err(e) => {
                     exit_status = 2;
                     exit_status = 2;
                     writeln!(io::stderr(), "{file_path:?}: {e}")?;
                     writeln!(io::stderr(), "{file_path:?}: {e}")?;
                 }
                 }
 
 
                 Ok(f) => {
                 Ok(f) => {
-                    if f.points_to_directory() && ! self.options.dir_action.treat_dirs_as_files() {
+                    if f.points_to_directory() && !self.options.dir_action.treat_dirs_as_files() {
                         trace!("matching on to_dir");
                         trace!("matching on to_dir");
                         match f.to_dir() {
                         match f.to_dir() {
-                            Ok(d)   => dirs.push(d),
+                            Ok(d) => dirs.push(d),
                             Err(e) if e.kind() == ErrorKind::PermissionDenied => {
                             Err(e) if e.kind() == ErrorKind::PermissionDenied => {
                                 warn!("Permission Denied: {e}");
                                 warn!("Permission Denied: {e}");
                                 exit(exits::PERMISSION_DENIED);
                                 exit(exits::PERMISSION_DENIED);
-                            },
-                            Err(e)  => writeln!(io::stderr(), "{file_path:?}: {e}")?,
+                            }
+                            Err(e) => writeln!(io::stderr(), "{file_path:?}: {e}")?,
                         }
                         }
-                    }
-                    else {
+                    } else {
                         files.push(f);
                         files.push(f);
                     }
                     }
                 }
                 }
@@ -217,52 +224,75 @@ impl<'args> Exa<'args> {
         self.print_dirs(dirs, no_files, is_only_dir, exit_status)
         self.print_dirs(dirs, no_files, is_only_dir, exit_status)
     }
     }
 
 
-    fn print_dirs(&mut self, dir_files: Vec<Dir>, mut first: bool, is_only_dir: bool, exit_status: i32) -> io::Result<i32> {
+    fn print_dirs(
+        &mut self,
+        dir_files: Vec<Dir>,
+        mut first: bool,
+        is_only_dir: bool,
+        exit_status: i32,
+    ) -> io::Result<i32> {
         for dir in dir_files {
         for dir in dir_files {
-
             // Put a gap between directories, or between the list of files and
             // Put a gap between directories, or between the list of files and
             // the first directory.
             // the first directory.
             if first {
             if first {
                 first = false;
                 first = false;
-            }
-            else {
+            } else {
                 writeln!(&mut self.writer)?;
                 writeln!(&mut self.writer)?;
             }
             }
 
 
-            if ! is_only_dir {
+            if !is_only_dir {
                 let mut bits = Vec::new();
                 let mut bits = Vec::new();
-                escape(dir.path.display().to_string(), &mut bits, Style::default(), Style::default());
+                escape(
+                    dir.path.display().to_string(),
+                    &mut bits,
+                    Style::default(),
+                    Style::default(),
+                );
                 writeln!(&mut self.writer, "{}:", ANSIStrings(&bits))?;
                 writeln!(&mut self.writer, "{}:", ANSIStrings(&bits))?;
             }
             }
 
 
             let mut children = Vec::new();
             let mut children = Vec::new();
             let git_ignore = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore;
             let git_ignore = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore;
-            for file in dir.files(self.options.filter.dot_filter, self.git.as_ref(), git_ignore, self.options.view.deref_links) {
+            for file in dir.files(
+                self.options.filter.dot_filter,
+                self.git.as_ref(),
+                git_ignore,
+                self.options.view.deref_links,
+            ) {
                 match file {
                 match file {
-                    Ok(file)        => children.push(file),
-                    Err((path, e))  => writeln!(io::stderr(), "[{}: {}]", path.display(), e)?,
+                    Ok(file) => children.push(file),
+                    Err((path, e)) => writeln!(io::stderr(), "[{}: {}]", path.display(), e)?,
                 }
                 }
-            };
+            }
 
 
             self.options.filter.filter_child_files(&mut children);
             self.options.filter.filter_child_files(&mut children);
             self.options.filter.sort_files(&mut children);
             self.options.filter.sort_files(&mut children);
 
 
             if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
             if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
-                let depth = dir.path.components().filter(|&c| c != Component::CurDir).count() + 1;
-                if ! recurse_opts.tree && ! recurse_opts.is_too_deep(depth) {
-
+                let depth = dir
+                    .path
+                    .components()
+                    .filter(|&c| c != Component::CurDir)
+                    .count()
+                    + 1;
+                if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {
                     let mut child_dirs = Vec::new();
                     let mut child_dirs = Vec::new();
-                    for child_dir in children.iter().filter(|f| f.is_directory() && ! f.is_all_all) {
+                    for child_dir in children
+                        .iter()
+                        .filter(|f| f.is_directory() && !f.is_all_all)
+                    {
                         match child_dir.to_dir() {
                         match child_dir.to_dir() {
-                            Ok(d)   => child_dirs.push(d),
-                            Err(e)  => writeln!(io::stderr(), "{}: {}", child_dir.path.display(), e)?,
+                            Ok(d) => child_dirs.push(d),
+                            Err(e) => {
+                                writeln!(io::stderr(), "{}: {}", child_dir.path.display(), e)?;
+                            }
                         }
                         }
                     }
                     }
 
 
                     self.print_files(Some(&dir), children)?;
                     self.print_files(Some(&dir), children)?;
                     match self.print_dirs(child_dirs, false, false, exit_status) {
                     match self.print_dirs(child_dirs, false, false, exit_status) {
-                        Ok(_)   => (),
-                        Err(e)  => return Err(e),
+                        Ok(_) => (),
+                        Err(e) => return Err(e),
                     }
                     }
                     continue;
                     continue;
                 }
                 }
@@ -281,19 +311,34 @@ impl<'args> Exa<'args> {
         }
         }
 
 
         let theme = &self.theme;
         let theme = &self.theme;
-        let View { ref mode, ref file_style, .. } = self.options.view;
+        let View {
+            ref mode,
+            ref file_style,
+            ..
+        } = self.options.view;
 
 
         match (mode, self.console_width) {
         match (mode, self.console_width) {
             (Mode::Grid(ref opts), Some(console_width)) => {
             (Mode::Grid(ref opts), Some(console_width)) => {
                 let filter = &self.options.filter;
                 let filter = &self.options.filter;
-                let r = grid::Render { files, theme, file_style, opts, console_width, filter };
+                let r = grid::Render {
+                    files,
+                    theme,
+                    file_style,
+                    opts,
+                    console_width,
+                    filter,
+                };
                 r.render(&mut self.writer)
                 r.render(&mut self.writer)
             }
             }
 
 
-            (Mode::Grid(_), None) |
-            (Mode::Lines,   _)    => {
+            (Mode::Grid(_), None) | (Mode::Lines, _) => {
                 let filter = &self.options.filter;
                 let filter = &self.options.filter;
-                let r = lines::Render { files, theme, file_style, filter };
+                let r = lines::Render {
+                    files,
+                    theme,
+                    file_style,
+                    filter,
+                };
                 r.render(&mut self.writer)
                 r.render(&mut self.writer)
             }
             }
 
 
@@ -303,7 +348,17 @@ impl<'args> Exa<'args> {
 
 
                 let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore;
                 let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore;
                 let git = self.git.as_ref();
                 let git = self.git.as_ref();
-                let r = details::Render { dir, files, theme, file_style, opts, recurse, filter, git_ignoring, git };
+                let r = details::Render {
+                    dir,
+                    files,
+                    theme,
+                    file_style,
+                    opts,
+                    recurse,
+                    filter,
+                    git_ignoring,
+                    git,
+                };
                 r.render(&mut self.writer)
                 r.render(&mut self.writer)
             }
             }
 
 
@@ -316,7 +371,19 @@ impl<'args> Exa<'args> {
                 let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore;
                 let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore;
                 let git = self.git.as_ref();
                 let git = self.git.as_ref();
 
 
-                let r = grid_details::Render { dir, files, theme, file_style, grid, details, filter, row_threshold, git_ignoring, git, console_width };
+                let r = grid_details::Render {
+                    dir,
+                    files,
+                    theme,
+                    file_style,
+                    grid,
+                    details,
+                    filter,
+                    row_threshold,
+                    git_ignoring,
+                    git,
+                    console_width,
+                };
                 r.render(&mut self.writer)
                 r.render(&mut self.writer)
             }
             }
 
 
@@ -327,14 +394,23 @@ impl<'args> Exa<'args> {
                 let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore;
                 let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore;
 
 
                 let git = self.git.as_ref();
                 let git = self.git.as_ref();
-                let r = details::Render { dir, files, theme, file_style, opts, recurse, filter, git_ignoring, git };
+                let r = details::Render {
+                    dir,
+                    files,
+                    theme,
+                    file_style,
+                    opts,
+                    recurse,
+                    filter,
+                    git_ignoring,
+                    git,
+                };
                 r.render(&mut self.writer)
                 r.render(&mut self.writer)
             }
             }
         }
         }
     }
     }
 }
 }
 
 
-
 mod exits {
 mod exits {
 
 
     /// Exit code for when exa runs OK.
     /// Exit code for when exa runs OK.

+ 31 - 29
src/options/dir_action.rs

@@ -1,13 +1,11 @@
 //! Parsing the options for `DirAction`.
 //! Parsing the options for `DirAction`.
 
 
 use crate::options::parser::MatchedFlags;
 use crate::options::parser::MatchedFlags;
-use crate::options::{flags, OptionsError, NumberSource};
+use crate::options::{flags, NumberSource, OptionsError};
 
 
 use crate::fs::dir_action::{DirAction, RecurseOptions};
 use crate::fs::dir_action::{DirAction, RecurseOptions};
 
 
-
 impl DirAction {
 impl DirAction {
-
     /// Determine which action to perform when trying to list a directory.
     /// Determine which action to perform when trying to list a directory.
     /// There are three possible actions, and they overlap somewhat: the
     /// There are three possible actions, and they overlap somewhat: the
     /// `--tree` flag is another form of recursion, so those two are allowed
     /// `--tree` flag is another form of recursion, so those two are allowed
@@ -15,17 +13,19 @@ impl DirAction {
     pub fn deduce(matches: &MatchedFlags<'_>, can_tree: bool) -> Result<Self, OptionsError> {
     pub fn deduce(matches: &MatchedFlags<'_>, can_tree: bool) -> Result<Self, OptionsError> {
         let recurse = matches.has(&flags::RECURSE)?;
         let recurse = matches.has(&flags::RECURSE)?;
         let as_file = matches.has(&flags::LIST_DIRS)?;
         let as_file = matches.has(&flags::LIST_DIRS)?;
-        let tree    = matches.has(&flags::TREE)?;
+        let tree = matches.has(&flags::TREE)?;
 
 
         if matches.is_strict() {
         if matches.is_strict() {
             // Early check for --level when it wouldn’t do anything
             // Early check for --level when it wouldn’t do anything
-            if ! recurse && ! tree && matches.count(&flags::LEVEL) > 0 {
-                return Err(OptionsError::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE));
-            }
-            else if recurse && as_file {
+            if !recurse && !tree && matches.count(&flags::LEVEL) > 0 {
+                return Err(OptionsError::Useless2(
+                    &flags::LEVEL,
+                    &flags::RECURSE,
+                    &flags::TREE,
+                ));
+            } else if recurse && as_file {
                 return Err(OptionsError::Conflict(&flags::RECURSE, &flags::LIST_DIRS));
                 return Err(OptionsError::Conflict(&flags::RECURSE, &flags::LIST_DIRS));
-            }
-            else if tree && as_file {
+            } else if tree && as_file {
                 return Err(OptionsError::Conflict(&flags::TREE, &flags::LIST_DIRS));
                 return Err(OptionsError::Conflict(&flags::TREE, &flags::LIST_DIRS));
             }
             }
         }
         }
@@ -34,22 +34,17 @@ impl DirAction {
             // Tree is only appropriate in details mode, so this has to
             // Tree is only appropriate in details mode, so this has to
             // examine the View, which should have already been deduced by now
             // examine the View, which should have already been deduced by now
             Ok(Self::Recurse(RecurseOptions::deduce(matches, true)?))
             Ok(Self::Recurse(RecurseOptions::deduce(matches, true)?))
-        }
-        else if recurse {
+        } else if recurse {
             Ok(Self::Recurse(RecurseOptions::deduce(matches, false)?))
             Ok(Self::Recurse(RecurseOptions::deduce(matches, false)?))
-        }
-        else if as_file {
+        } else if as_file {
             Ok(Self::AsFile)
             Ok(Self::AsFile)
-        }
-        else {
+        } else {
             Ok(Self::List)
             Ok(Self::List)
         }
         }
     }
     }
 }
 }
 
 
-
 impl RecurseOptions {
 impl RecurseOptions {
-
     /// Determine which files should be recursed into, based on the `--level`
     /// Determine which files should be recursed into, based on the `--level`
     /// flag’s value, and whether the `--tree` flag was passed, which was
     /// flag’s value, and whether the `--tree` flag was passed, which was
     /// determined earlier. The maximum level should be a number, and this
     /// determined earlier. The maximum level should be a number, and this
@@ -58,22 +53,24 @@ impl RecurseOptions {
         if let Some(level) = matches.get(&flags::LEVEL)? {
         if let Some(level) = matches.get(&flags::LEVEL)? {
             let arg_str = level.to_string_lossy();
             let arg_str = level.to_string_lossy();
             match arg_str.parse() {
             match arg_str.parse() {
-                Ok(l) => {
-                    Ok(Self { tree, max_depth: Some(l) })
-                }
+                Ok(l) => Ok(Self {
+                    tree,
+                    max_depth: Some(l),
+                }),
                 Err(e) => {
                 Err(e) => {
                     let source = NumberSource::Arg(&flags::LEVEL);
                     let source = NumberSource::Arg(&flags::LEVEL);
                     Err(OptionsError::FailedParse(arg_str.to_string(), source, e))
                     Err(OptionsError::FailedParse(arg_str.to_string(), source, e))
                 }
                 }
             }
             }
-        }
-        else {
-            Ok(Self { tree, max_depth: None })
+        } else {
+            Ok(Self {
+                tree,
+                max_depth: None,
+            })
         }
         }
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod test {
 mod test {
     use super::*;
     use super::*;
@@ -88,15 +85,21 @@ mod test {
                 use crate::options::test::parse_for_test;
                 use crate::options::test::parse_for_test;
                 use crate::options::test::Strictnesses::*;
                 use crate::options::test::Strictnesses::*;
 
 
-                static TEST_ARGS: &[&Arg] = &[&flags::RECURSE, &flags::LIST_DIRS, &flags::TREE, &flags::LEVEL ];
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, true)) {
+                static TEST_ARGS: &[&Arg] = &[
+                    &flags::RECURSE,
+                    &flags::LIST_DIRS,
+                    &flags::TREE,
+                    &flags::LEVEL,
+                ];
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf, true)
+                }) {
                     assert_eq!(result, $result);
                     assert_eq!(result, $result);
                 }
                 }
             }
             }
         };
         };
     }
     }
 
 
-
     // Default behaviour
     // Default behaviour
     test!(empty:           DirAction <- [];               Both => Ok(DirAction::List));
     test!(empty:           DirAction <- [];               Both => Ok(DirAction::List));
 
 
@@ -125,7 +128,6 @@ mod test {
     test!(dirs_tree_2:     DirAction <- ["--list-dirs", "--tree"];    Complain => Err(OptionsError::Conflict(&flags::TREE,    &flags::LIST_DIRS)));
     test!(dirs_tree_2:     DirAction <- ["--list-dirs", "--tree"];    Complain => Err(OptionsError::Conflict(&flags::TREE,    &flags::LIST_DIRS)));
     test!(just_level_2:    DirAction <- ["--level=4"];                Complain => Err(OptionsError::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE)));
     test!(just_level_2:    DirAction <- ["--level=4"];                Complain => Err(OptionsError::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE)));
 
 
-
     // Overriding levels
     // Overriding levels
     test!(overriding_1:    DirAction <- ["-RL=6", "-L=7"];                Last => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(7) })));
     test!(overriding_1:    DirAction <- ["-RL=6", "-L=7"];                Last => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(7) })));
     test!(overriding_2:    DirAction <- ["-RL=6", "-L=7"];            Complain => Err(OptionsError::Duplicate(Flag::Short(b'L'), Flag::Short(b'L'))));
     test!(overriding_2:    DirAction <- ["-RL=6", "-L=7"];            Complain => Err(OptionsError::Duplicate(Flag::Short(b'L'), Flag::Short(b'L'))));

+ 12 - 13
src/options/error.rs

@@ -5,11 +5,9 @@ use std::num::ParseIntError;
 use crate::options::flags;
 use crate::options::flags;
 use crate::options::parser::{Arg, Flag, ParseError};
 use crate::options::parser::{Arg, Flag, ParseError};
 
 
-
 /// Something wrong with the combination of options the user has picked.
 /// Something wrong with the combination of options the user has picked.
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub enum OptionsError {
 pub enum OptionsError {
-
     /// There was an error (from `getopts`) parsing the arguments.
     /// There was an error (from `getopts`) parsing the arguments.
     Parse(ParseError),
     Parse(ParseError),
 
 
@@ -46,7 +44,6 @@ pub enum OptionsError {
 /// The source of a string that failed to be parsed as a number.
 /// The source of a string that failed to be parsed as a number.
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub enum NumberSource {
 pub enum NumberSource {
-
     /// It came... from a command-line argument!
     /// It came... from a command-line argument!
     Arg(&'static Arg),
     Arg(&'static Arg),
 
 
@@ -73,12 +70,18 @@ impl fmt::Display for OptionsError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use crate::options::parser::TakesValue;
         use crate::options::parser::TakesValue;
 
 
-        match self {
+        #[rustfmt::skip]
+        return match self {
             Self::BadArgument(arg, attempt) => {
             Self::BadArgument(arg, attempt) => {
                 if let TakesValue::Necessary(Some(values)) = arg.takes_value {
                 if let TakesValue::Necessary(Some(values)) = arg.takes_value {
-                    write!(f, "Option {} has no {:?} setting ({})", arg, attempt, Choices(values))
-                }
-                else {
+                    write!(
+                        f,
+                        "Option {} has no {:?} setting ({})",
+                        arg,
+                        attempt,
+                        Choices(values)
+                    )
+                } else {
                     write!(f, "Option {arg} has no {attempt:?} setting")
                     write!(f, "Option {arg} has no {attempt:?} setting")
                 }
                 }
             }
             }
@@ -93,12 +96,11 @@ impl fmt::Display for OptionsError {
             Self::TreeAllAll                 => write!(f, "Option --tree is useless given --all --all"),
             Self::TreeAllAll                 => write!(f, "Option --tree is useless given --all --all"),
             Self::FailedParse(s, n, e)       => write!(f, "Value {s:?} not valid for {n}: {e}"),
             Self::FailedParse(s, n, e)       => write!(f, "Value {s:?} not valid for {n}: {e}"),
             Self::FailedGlobPattern(ref e)   => write!(f, "Failed to parse glob pattern: {e}"),
             Self::FailedGlobPattern(ref e)   => write!(f, "Failed to parse glob pattern: {e}"),
-        }
+        };
     }
     }
 }
 }
 
 
 impl OptionsError {
 impl OptionsError {
-
     /// Try to second-guess what the user was trying to do, depending on what
     /// Try to second-guess what the user was trying to do, depending on what
     /// went wrong.
     /// went wrong.
     pub fn suggestion(&self) -> Option<&'static str> {
     pub fn suggestion(&self) -> Option<&'static str> {
@@ -110,14 +112,11 @@ impl OptionsError {
             Self::Parse(ParseError::NeedsValue { ref flag, .. }) if *flag == Flag::Short(b't') => {
             Self::Parse(ParseError::NeedsValue { ref flag, .. }) if *flag == Flag::Short(b't') => {
                 Some("To sort newest files last, try \"--sort newest\", or just \"-snew\"")
                 Some("To sort newest files last, try \"--sort newest\", or just \"-snew\"")
             }
             }
-            _ => {
-                None
-            }
+            _ => None,
         }
         }
     }
     }
 }
 }
 
 
-
 /// A list of legal choices for an argument-taking option.
 /// A list of legal choices for an argument-taking option.
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub struct Choices(pub &'static [&'static str]);
 pub struct Choices(pub &'static [&'static str]);

+ 27 - 16
src/options/file_name.rs

@@ -1,9 +1,8 @@
-use crate::options::{flags, OptionsError, NumberSource};
 use crate::options::parser::MatchedFlags;
 use crate::options::parser::MatchedFlags;
 use crate::options::vars::{self, Vars};
 use crate::options::vars::{self, Vars};
+use crate::options::{flags, NumberSource, OptionsError};
 
 
-use crate::output::file_name::{Options, Classify, ShowIcons, EmbedHyperlinks};
-
+use crate::output::file_name::{Classify, EmbedHyperlinks, Options, ShowIcons};
 
 
 impl Options {
 impl Options {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
@@ -11,7 +10,11 @@ impl Options {
         let show_icons = ShowIcons::deduce(matches, vars)?;
         let show_icons = ShowIcons::deduce(matches, vars)?;
         let embed_hyperlinks = EmbedHyperlinks::deduce(matches)?;
         let embed_hyperlinks = EmbedHyperlinks::deduce(matches)?;
 
 
-        Ok(Self { classify, show_icons, embed_hyperlinks })
+        Ok(Self {
+            classify,
+            show_icons,
+            embed_hyperlinks,
+        })
     }
     }
 }
 }
 
 
@@ -19,8 +22,11 @@ impl Classify {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
         let flagged = matches.has(&flags::CLASSIFY)?;
         let flagged = matches.has(&flags::CLASSIFY)?;
 
 
-        if flagged { Ok(Self::AddFileIndicators) }
-              else { Ok(Self::JustFilenames) }
+        if flagged {
+            Ok(Self::AddFileIndicators)
+        } else {
+            Ok(Self::JustFilenames)
+        }
     }
     }
 }
 }
 
 
@@ -28,19 +34,21 @@ impl ShowIcons {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
         if matches.has(&flags::NO_ICONS)? || !matches.has(&flags::ICONS)? {
         if matches.has(&flags::NO_ICONS)? || !matches.has(&flags::ICONS)? {
             Ok(Self::Off)
             Ok(Self::Off)
-        }
-        else if let Some(columns) = vars.get_with_fallback(vars::EZA_ICON_SPACING, vars::EXA_ICON_SPACING).and_then(|s| s.into_string().ok()) {
+        } else if let Some(columns) = vars
+            .get_with_fallback(vars::EZA_ICON_SPACING, vars::EXA_ICON_SPACING)
+            .and_then(|s| s.into_string().ok())
+        {
             match columns.parse() {
             match columns.parse() {
-                Ok(width) => {
-                    Ok(Self::On(width))
-                }
+                Ok(width) => Ok(Self::On(width)),
                 Err(e) => {
                 Err(e) => {
-                    let source = NumberSource::Env(vars.source(vars::EZA_ICON_SPACING, vars::EXA_ICON_SPACING).unwrap());
+                    let source = NumberSource::Env(
+                        vars.source(vars::EZA_ICON_SPACING, vars::EXA_ICON_SPACING)
+                            .unwrap(),
+                    );
                     Err(OptionsError::FailedParse(columns, source, e))
                     Err(OptionsError::FailedParse(columns, source, e))
                 }
                 }
             }
             }
-        }
-        else {
+        } else {
             Ok(Self::On(1))
             Ok(Self::On(1))
         }
         }
     }
     }
@@ -50,7 +58,10 @@ impl EmbedHyperlinks {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
         let flagged = matches.has(&flags::HYPERLINK)?;
         let flagged = matches.has(&flags::HYPERLINK)?;
 
 
-        if flagged { Ok(Self::On) }
-              else { Ok(Self::Off) }
+        if flagged {
+            Ok(Self::On)
+        } else {
+            Ok(Self::Off)
+        }
     }
     }
 }
 }

+ 59 - 84
src/options/filter.rs

@@ -1,109 +1,83 @@
 //! Parsing the options for `FileFilter`.
 //! Parsing the options for `FileFilter`.
 
 
+use crate::fs::filter::{
+    FileFilter, FileFilterFlags, GitIgnore, IgnorePatterns, SortCase, SortField,
+};
 use crate::fs::DotFilter;
 use crate::fs::DotFilter;
-use crate::fs::filter::{FileFilter,FileFilterFlags, SortField, SortCase, IgnorePatterns, GitIgnore};
 
 
-use crate::options::{flags, OptionsError};
 use crate::options::parser::MatchedFlags;
 use crate::options::parser::MatchedFlags;
-
+use crate::options::{flags, OptionsError};
 
 
 impl FileFilter {
 impl FileFilter {
-
     /// Determines which of all the file filter options to use.
     /// Determines which of all the file filter options to use.
     pub fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     pub fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
         use FileFilterFlags as FFF;
         use FileFilterFlags as FFF;
-        let mut filter_flags:Vec<FileFilterFlags> = vec![];
-            
-        for (has,flag) in &[
+        let mut filter_flags: Vec<FileFilterFlags> = vec![];
+
+        for (has, flag) in &[
             (matches.has(&flags::REVERSE)?, FFF::Reverse),
             (matches.has(&flags::REVERSE)?, FFF::Reverse),
             (matches.has(&flags::ONLY_DIRS)?, FFF::OnlyDirs),
             (matches.has(&flags::ONLY_DIRS)?, FFF::OnlyDirs),
             (matches.has(&flags::ONLY_FILES)?, FFF::OnlyFiles),
             (matches.has(&flags::ONLY_FILES)?, FFF::OnlyFiles),
         ] {
         ] {
-            if *has { 
+            if *has {
                 filter_flags.push(flag.clone());
                 filter_flags.push(flag.clone());
             }
             }
         }
         }
 
 
-        Ok(Self {
+        #[rustfmt::skip]
+        return Ok(Self {
             list_dirs_first:  matches.has(&flags::DIRS_FIRST)?,
             list_dirs_first:  matches.has(&flags::DIRS_FIRST)?,
             flags: filter_flags,
             flags: filter_flags,
             sort_field:       SortField::deduce(matches)?,
             sort_field:       SortField::deduce(matches)?,
             dot_filter:       DotFilter::deduce(matches)?,
             dot_filter:       DotFilter::deduce(matches)?,
             ignore_patterns:  IgnorePatterns::deduce(matches)?,
             ignore_patterns:  IgnorePatterns::deduce(matches)?,
             git_ignore:       GitIgnore::deduce(matches)?,
             git_ignore:       GitIgnore::deduce(matches)?,
-        })
+        });
     }
     }
 }
 }
 
 
 impl SortField {
 impl SortField {
-
     /// Determines which sort field to use based on the `--sort` argument.
     /// Determines which sort field to use based on the `--sort` argument.
     /// This argument’s value can be one of several flags, listed above.
     /// This argument’s value can be one of several flags, listed above.
     /// Returns the default sort field if none is given, or `Err` if the
     /// Returns the default sort field if none is given, or `Err` if the
     /// value doesn’t correspond to a sort field we know about.
     /// value doesn’t correspond to a sort field we know about.
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
-        let Some(word) = matches.get(&flags::SORT)? else { return Ok(Self::default()) };
+        let Some(word) = matches.get(&flags::SORT)? else {
+            return Ok(Self::default());
+        };
 
 
         // Get String because we can’t match an OsStr
         // Get String because we can’t match an OsStr
-        let Some(word) = word.to_str() else { return Err(OptionsError::BadArgument(&flags::SORT, word.into())) };
+        let Some(word) = word.to_str() else {
+            return Err(OptionsError::BadArgument(&flags::SORT, word.into()));
+        };
 
 
         let field = match word {
         let field = match word {
-            "name" | "filename" => {
-                Self::Name(SortCase::AaBbCc)
-            }
-            "Name" | "Filename" => {
-                Self::Name(SortCase::ABCabc)
-            }
-            ".name" | ".filename" => {
-                Self::NameMixHidden(SortCase::AaBbCc)
-            }
-            ".Name" | ".Filename" => {
-                Self::NameMixHidden(SortCase::ABCabc)
-            }
-            "size" | "filesize" => {
-                Self::Size
-            }
-            "ext" | "extension" => {
-                Self::Extension(SortCase::AaBbCc)
-            }
-            "Ext" | "Extension" => {
-                Self::Extension(SortCase::ABCabc)
-            }
+            "name" | "filename" => Self::Name(SortCase::AaBbCc),
+            "Name" | "Filename" => Self::Name(SortCase::ABCabc),
+            ".name" | ".filename" => Self::NameMixHidden(SortCase::AaBbCc),
+            ".Name" | ".Filename" => Self::NameMixHidden(SortCase::ABCabc),
+            "size" | "filesize" => Self::Size,
+            "ext" | "extension" => Self::Extension(SortCase::AaBbCc),
+            "Ext" | "Extension" => Self::Extension(SortCase::ABCabc),
 
 
             // “new” sorts oldest at the top and newest at the bottom; “old”
             // “new” sorts oldest at the top and newest at the bottom; “old”
             // sorts newest at the top and oldest at the bottom. I think this
             // sorts newest at the top and oldest at the bottom. I think this
             // is the right way round to do this: “size” puts the smallest at
             // is the right way round to do this: “size” puts the smallest at
             // the top and the largest at the bottom, doesn’t it?
             // the top and the largest at the bottom, doesn’t it?
-            "date" | "time" | "mod" | "modified" | "new" | "newest" => {
-                Self::ModifiedDate
-            }
+            "date" | "time" | "mod" | "modified" | "new" | "newest" => Self::ModifiedDate,
 
 
             // Similarly, “age” means that files with the least age (the
             // Similarly, “age” means that files with the least age (the
             // newest files) get sorted at the top, and files with the most
             // newest files) get sorted at the top, and files with the most
             // age (the oldest) at the bottom.
             // age (the oldest) at the bottom.
-            "age" | "old" | "oldest" => {
-                Self::ModifiedAge
-            }
+            "age" | "old" | "oldest" => Self::ModifiedAge,
 
 
-            "ch" | "changed" => {
-                Self::ChangedDate
-            }
-            "acc" | "accessed" => {
-                Self::AccessedDate
-            }
-            "cr" | "created" => {
-                Self::CreatedDate
-            }
+            "ch" | "changed" => Self::ChangedDate,
+            "acc" | "accessed" => Self::AccessedDate,
+            "cr" | "created" => Self::CreatedDate,
             #[cfg(unix)]
             #[cfg(unix)]
-            "inode" => {
-                Self::FileInode
-            }
-            "type" => {
-                Self::FileType
-            }
-            "none" => {
-                Self::Unsorted
-            }
+            "inode" => Self::FileInode,
+            "type" => Self::FileType,
+            "none" => Self::Unsorted,
             _ => {
             _ => {
                 return Err(OptionsError::BadArgument(&flags::SORT, word.into()));
                 return Err(OptionsError::BadArgument(&flags::SORT, word.into()));
             }
             }
@@ -113,7 +87,6 @@ impl SortField {
     }
     }
 }
 }
 
 
-
 // I’ve gone back and forth between whether to sort case-sensitively or
 // I’ve gone back and forth between whether to sort case-sensitively or
 // insensitively by default. The default string sort in most programming
 // insensitively by default. The default string sort in most programming
 // languages takes each character’s ASCII value into account, sorting
 // languages takes each character’s ASCII value into account, sorting
@@ -151,9 +124,7 @@ impl Default for SortField {
     }
     }
 }
 }
 
 
-
 impl DotFilter {
 impl DotFilter {
-
     /// Determines the dot filter based on how many `--all` options were
     /// Determines the dot filter based on how many `--all` options were
     /// given: one will show dotfiles, but two will show `.` and `..` too.
     /// given: one will show dotfiles, but two will show `.` and `..` too.
     /// --almost-all is equivalent to --all, included for compatibility with
     /// --almost-all is equivalent to --all, included for compatibility with
@@ -175,28 +146,29 @@ impl DotFilter {
             // either a single --all or at least one --almost-all is given
             // either a single --all or at least one --almost-all is given
             (1, _) | (0, true) => Ok(Self::Dotfiles),
             (1, _) | (0, true) => Ok(Self::Dotfiles),
             // more than one --all
             // more than one --all
-            (c, _) => if matches.count(&flags::TREE) > 0 {
-                Err(OptionsError::TreeAllAll)
-            } else if matches.is_strict() && c > 2 {
-                Err(OptionsError::Conflict(&flags::ALL, &flags::ALL))
-            } else {
-                Ok(Self::DotfilesAndDots)
-            },
+            (c, _) => {
+                if matches.count(&flags::TREE) > 0 {
+                    Err(OptionsError::TreeAllAll)
+                } else if matches.is_strict() && c > 2 {
+                    Err(OptionsError::Conflict(&flags::ALL, &flags::ALL))
+                } else {
+                    Ok(Self::DotfilesAndDots)
+                }
+            }
         }
         }
     }
     }
 }
 }
 
 
-
 impl IgnorePatterns {
 impl IgnorePatterns {
-
     /// Determines the set of glob patterns to use based on the
     /// Determines the set of glob patterns to use based on the
     /// `--ignore-glob` argument’s value. This is a list of strings
     /// `--ignore-glob` argument’s value. This is a list of strings
     /// separated by pipe (`|`) characters, given in any order.
     /// separated by pipe (`|`) characters, given in any order.
     pub fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     pub fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
-
         // If there are no inputs, we return a set of patterns that doesn’t
         // If there are no inputs, we return a set of patterns that doesn’t
         // match anything, rather than, say, `None`.
         // match anything, rather than, say, `None`.
-        let Some(inputs) = matches.get(&flags::IGNORE_GLOB)? else { return Ok(Self::empty()) };
+        let Some(inputs) = matches.get(&flags::IGNORE_GLOB)? else {
+            return Ok(Self::empty());
+        };
 
 
         // Awkwardly, though, a glob pattern can be invalid, and we need to
         // Awkwardly, though, a glob pattern can be invalid, and we need to
         // deal with invalid patterns somehow.
         // deal with invalid patterns somehow.
@@ -205,31 +177,28 @@ impl IgnorePatterns {
         // It can actually return more than one glob error,
         // It can actually return more than one glob error,
         // but we only use one. (TODO)
         // but we only use one. (TODO)
         match errors.pop() {
         match errors.pop() {
-            Some(e)  => Err(e.into()),
-            None     => Ok(patterns),
+            Some(e) => Err(e.into()),
+            None => Ok(patterns),
         }
         }
     }
     }
 }
 }
 
 
-
 impl GitIgnore {
 impl GitIgnore {
     pub fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     pub fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
         if matches.has(&flags::GIT_IGNORE)? {
         if matches.has(&flags::GIT_IGNORE)? {
             Ok(Self::CheckAndIgnore)
             Ok(Self::CheckAndIgnore)
-        }
-        else {
+        } else {
             Ok(Self::Off)
             Ok(Self::Off)
         }
         }
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod test {
 mod test {
     use super::*;
     use super::*;
-    use std::ffi::OsString;
     use crate::options::flags;
     use crate::options::flags;
     use crate::options::parser::Flag;
     use crate::options::parser::Flag;
+    use std::ffi::OsString;
 
 
     macro_rules! test {
     macro_rules! test {
         ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
         ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
@@ -239,8 +208,17 @@ mod test {
                 use crate::options::test::parse_for_test;
                 use crate::options::test::parse_for_test;
                 use crate::options::test::Strictnesses::*;
                 use crate::options::test::Strictnesses::*;
 
 
-                static TEST_ARGS: &[&Arg] = &[ &flags::SORT, &flags::ALL, &flags::ALMOST_ALL, &flags::TREE, &flags::IGNORE_GLOB, &flags::GIT_IGNORE ];
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
+                static TEST_ARGS: &[&Arg] = &[
+                    &flags::SORT,
+                    &flags::ALL,
+                    &flags::ALMOST_ALL,
+                    &flags::TREE,
+                    &flags::IGNORE_GLOB,
+                    &flags::GIT_IGNORE,
+                ];
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf)
+                }) {
                     assert_eq!(result, $result);
                     assert_eq!(result, $result);
                 }
                 }
             }
             }
@@ -278,7 +256,6 @@ mod test {
         test!(overridden_4:  SortField <- ["--sort", "none",  "--sort=Extension"];  Complain => Err(OptionsError::Duplicate(Flag::Long("sort"), Flag::Long("sort"))));
         test!(overridden_4:  SortField <- ["--sort", "none",  "--sort=Extension"];  Complain => Err(OptionsError::Duplicate(Flag::Long("sort"), Flag::Long("sort"))));
     }
     }
 
 
-
     mod dot_filters {
     mod dot_filters {
         use super::*;
         use super::*;
 
 
@@ -304,7 +281,6 @@ mod test {
         test!(almost_all_all_2: DotFilter <- ["-Aaa"];         Both => Ok(DotFilter::DotfilesAndDots));
         test!(almost_all_all_2: DotFilter <- ["-Aaa"];         Both => Ok(DotFilter::DotfilesAndDots));
     }
     }
 
 
-
     mod ignore_patterns {
     mod ignore_patterns {
         use super::*;
         use super::*;
         use std::iter::FromIterator;
         use std::iter::FromIterator;
@@ -326,7 +302,6 @@ mod test {
         test!(overridden_4: IgnorePatterns <- ["-I", "*.OGG", "-I*.MP3"];      Complain => Err(OptionsError::Duplicate(Flag::Short(b'I'), Flag::Short(b'I'))));
         test!(overridden_4: IgnorePatterns <- ["-I", "*.OGG", "-I*.MP3"];      Complain => Err(OptionsError::Duplicate(Flag::Short(b'I'), Flag::Short(b'I'))));
     }
     }
 
 
-
     mod git_ignores {
     mod git_ignores {
         use super::*;
         use super::*;
 
 

+ 0 - 1
src/options/flags.rs

@@ -1,6 +1,5 @@
 use crate::options::parser::{Arg, Args, TakesValue, Values};
 use crate::options::parser::{Arg, Args, TakesValue, Values};
 
 
-
 // exa options
 // exa options
 pub static VERSION: Arg = Arg { short: Some(b'v'), long: "version",  takes_value: TakesValue::Forbidden };
 pub static VERSION: Arg = Arg { short: Some(b'v'), long: "version",  takes_value: TakesValue::Forbidden };
 pub static HELP:    Arg = Arg { short: Some(b'?'), long: "help",     takes_value: TakesValue::Forbidden };
 pub static HELP:    Arg = Arg { short: Some(b'?'), long: "help",     takes_value: TakesValue::Forbidden };

+ 6 - 11
src/options/help.rs

@@ -4,7 +4,6 @@ use crate::fs::feature::xattr;
 use crate::options::flags;
 use crate::options::flags;
 use crate::options::parser::MatchedFlags;
 use crate::options::parser::MatchedFlags;
 
 
-
 static USAGE_PART1: &str = "Usage:
 static USAGE_PART1: &str = "Usage:
   eza [options] [files...]
   eza [options] [files...]
 
 
@@ -72,9 +71,9 @@ static GIT_VIEW_HELP:   &str = "  \
   --git                    list each file's Git status, if tracked or ignored
   --git                    list each file's Git status, if tracked or ignored
   --no-git                 suppress Git status (always overrides --git, --git-repos, --git-repos-no-status)
   --no-git                 suppress Git status (always overrides --git, --git-repos, --git-repos-no-status)
   --git-repos              list root of git-tree status";
   --git-repos              list root of git-tree status";
-static EXTENDED_HELP:   &str = "  \
+static EXTENDED_HELP: &str = "  \
   -@, --extended           list each file's extended attributes and sizes";
   -@, --extended           list each file's extended attributes and sizes";
-static SECATTR_HELP:    &str = "  \
+static SECATTR_HELP: &str = "  \
   -Z, --context            list each file's security context";
   -Z, --context            list each file's security context";
 
 
 /// All the information needed to display the help text, which depends
 /// All the information needed to display the help text, which depends
@@ -84,7 +83,6 @@ static SECATTR_HELP:    &str = "  \
 pub struct HelpString;
 pub struct HelpString;
 
 
 impl HelpString {
 impl HelpString {
-
     /// Determines how to show help, if at all, based on the user’s
     /// Determines how to show help, if at all, based on the user’s
     /// command-line arguments. This one works backwards from the other
     /// command-line arguments. This one works backwards from the other
     /// ‘deduce’ functions, returning Err if help needs to be shown.
     /// ‘deduce’ functions, returning Err if help needs to be shown.
@@ -95,15 +93,13 @@ impl HelpString {
     pub fn deduce(matches: &MatchedFlags<'_>) -> Option<Self> {
     pub fn deduce(matches: &MatchedFlags<'_>) -> Option<Self> {
         if matches.count(&flags::HELP) > 0 {
         if matches.count(&flags::HELP) > 0 {
             Some(Self)
             Some(Self)
-        }
-        else {
+        } else {
             None
             None
         }
         }
     }
     }
 }
 }
 
 
 impl fmt::Display for HelpString {
 impl fmt::Display for HelpString {
-
     /// Format this help options into an actual string of help
     /// Format this help options into an actual string of help
     /// text to be displayed to the user.
     /// text to be displayed to the user.
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
@@ -128,7 +124,6 @@ impl fmt::Display for HelpString {
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod test {
 mod test {
     use crate::options::{Options, OptionsResult};
     use crate::options::{Options, OptionsResult};
@@ -136,14 +131,14 @@ mod test {
 
 
     #[test]
     #[test]
     fn help() {
     fn help() {
-        let args = vec![ OsStr::new("--help") ];
+        let args = vec![OsStr::new("--help")];
         let opts = Options::parse(args, &None);
         let opts = Options::parse(args, &None);
         assert!(matches!(opts, OptionsResult::Help(_)));
         assert!(matches!(opts, OptionsResult::Help(_)));
     }
     }
 
 
     #[test]
     #[test]
     fn help_with_file() {
     fn help_with_file() {
-        let args = vec![ OsStr::new("--help"), OsStr::new("me") ];
+        let args = vec![OsStr::new("--help"), OsStr::new("me")];
         let opts = Options::parse(args, &None);
         let opts = Options::parse(args, &None);
         assert!(matches!(opts, OptionsResult::Help(_)));
         assert!(matches!(opts, OptionsResult::Help(_)));
     }
     }
@@ -152,6 +147,6 @@ mod test {
     fn unhelpful() {
     fn unhelpful() {
         let args = vec![];
         let args = vec![];
         let opts = Options::parse(args, &None);
         let opts = Options::parse(args, &None);
-        assert!(! matches!(opts, OptionsResult::Help(_)))  // no help when --help isn’t passed
+        assert!(!matches!(opts, OptionsResult::Help(_))) // no help when --help isn’t passed
     }
     }
 }
 }

+ 42 - 22
src/options/mod.rs

@@ -68,23 +68,23 @@
 //! --grid --long` shouldn’t complain about `--long` being given twice when
 //! --grid --long` shouldn’t complain about `--long` being given twice when
 //! it’s clear what the user wants.
 //! it’s clear what the user wants.
 
 
-
 use std::ffi::OsStr;
 use std::ffi::OsStr;
 
 
 use crate::fs::dir_action::DirAction;
 use crate::fs::dir_action::DirAction;
 use crate::fs::filter::{FileFilter, GitIgnore};
 use crate::fs::filter::{FileFilter, GitIgnore};
-use crate::output::{View, Mode, details, grid_details};
+use crate::output::{details, grid_details, Mode, View};
 use crate::theme::Options as ThemeOptions;
 use crate::theme::Options as ThemeOptions;
 
 
 mod dir_action;
 mod dir_action;
 mod file_name;
 mod file_name;
 mod filter;
 mod filter;
+#[rustfmt::skip] // this module becomes unreadable with rustfmt
 mod flags;
 mod flags;
 mod theme;
 mod theme;
 mod view;
 mod view;
 
 
 mod error;
 mod error;
-pub use self::error::{OptionsError, NumberSource};
+pub use self::error::{NumberSource, OptionsError};
 
 
 mod help;
 mod help;
 use self::help::HelpString;
 use self::help::HelpString;
@@ -98,12 +98,10 @@ pub use self::vars::Vars;
 mod version;
 mod version;
 use self::version::VersionString;
 use self::version::VersionString;
 
 
-
 /// These **options** represent a parsed, error-checked versions of the
 /// These **options** represent a parsed, error-checked versions of the
 /// user’s command-line options.
 /// user’s command-line options.
 #[derive(Debug)]
 #[derive(Debug)]
 pub struct Options {
 pub struct Options {
-
     /// The action to perform when encountering a directory rather than a
     /// The action to perform when encountering a directory rather than a
     /// regular file.
     /// regular file.
     pub dir_action: DirAction,
     pub dir_action: DirAction,
@@ -122,17 +120,18 @@ pub struct Options {
 }
 }
 
 
 impl Options {
 impl Options {
-
     /// Parse the given iterator of command-line strings into an Options
     /// Parse the given iterator of command-line strings into an Options
     /// struct and a list of free filenames, using the environment variables
     /// struct and a list of free filenames, using the environment variables
     /// for extra options.
     /// for extra options.
     #[allow(unused_results)]
     #[allow(unused_results)]
     pub fn parse<'args, I, V>(args: I, vars: &V) -> OptionsResult<'args>
     pub fn parse<'args, I, V>(args: I, vars: &V) -> OptionsResult<'args>
-    where I: IntoIterator<Item = &'args OsStr>,
-          V: Vars,
+    where
+        I: IntoIterator<Item = &'args OsStr>,
+        V: Vars,
     {
     {
         use crate::options::parser::{Matches, Strictness};
         use crate::options::parser::{Matches, Strictness};
 
 
+        #[rustfmt::skip]
         let strictness = match vars.get_with_fallback(vars::EZA_STRICT, vars::EXA_STRICT) {
         let strictness = match vars.get_with_fallback(vars::EZA_STRICT, vars::EXA_STRICT) {
             None                         => Strictness::UseLastArguments,
             None                         => Strictness::UseLastArguments,
             Some(ref t) if t.is_empty()  => Strictness::UseLastArguments,
             Some(ref t) if t.is_empty()  => Strictness::UseLastArguments,
@@ -140,8 +139,8 @@ impl Options {
         };
         };
 
 
         let Matches { flags, frees } = match flags::ALL_ARGS.parse(args, strictness) {
         let Matches { flags, frees } = match flags::ALL_ARGS.parse(args, strictness) {
-            Ok(m)    => m,
-            Err(pe)  => return OptionsResult::InvalidOptions(OptionsError::Parse(pe)),
+            Ok(m) => m,
+            Err(pe) => return OptionsResult::InvalidOptions(OptionsError::Parse(pe)),
         };
         };
 
 
         if let Some(help) = HelpString::deduce(&flags) {
         if let Some(help) = HelpString::deduce(&flags) {
@@ -153,8 +152,8 @@ impl Options {
         }
         }
 
 
         match Self::deduce(&flags, vars) {
         match Self::deduce(&flags, vars) {
-            Ok(options)  => OptionsResult::Ok(options, frees),
-            Err(oe)      => OptionsResult::InvalidOptions(oe),
+            Ok(options) => OptionsResult::Ok(options, frees),
+            Err(oe) => OptionsResult::InvalidOptions(oe),
         }
         }
     }
     }
 
 
@@ -167,8 +166,18 @@ impl Options {
         }
         }
 
 
         match self.view.mode {
         match self.view.mode {
-            Mode::Details(details::Options { table: Some(ref table), .. }) |
-            Mode::GridDetails(grid_details::Options { details: details::Options { table: Some(ref table), .. }, .. }) => table.columns.git,
+            Mode::Details(details::Options {
+                table: Some(ref table),
+                ..
+            })
+            | Mode::GridDetails(grid_details::Options {
+                details:
+                    details::Options {
+                        table: Some(ref table),
+                        ..
+                    },
+                ..
+            }) => table.columns.git,
             _ => false,
             _ => false,
         }
         }
     }
     }
@@ -176,8 +185,11 @@ impl Options {
     /// Determines the complete set of options based on the given command-line
     /// Determines the complete set of options based on the given command-line
     /// arguments, after they’ve been parsed.
     /// arguments, after they’ve been parsed.
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
-        if cfg!(not(feature = "git")) &&
-                matches.has_where_any(|f| f.matches(&flags::GIT) || f.matches(&flags::GIT_IGNORE)).is_some() {
+        if cfg!(not(feature = "git"))
+            && matches
+                .has_where_any(|f| f.matches(&flags::GIT) || f.matches(&flags::GIT_IGNORE))
+                .is_some()
+        {
             return Err(OptionsError::Unsupported(String::from(
             return Err(OptionsError::Unsupported(String::from(
                 "Options --git and --git-ignore can't be used because `git` feature was disabled in this build of exa"
                 "Options --git and --git-ignore can't be used because `git` feature was disabled in this build of exa"
             )));
             )));
@@ -188,15 +200,18 @@ impl Options {
         let filter = FileFilter::deduce(matches)?;
         let filter = FileFilter::deduce(matches)?;
         let theme = ThemeOptions::deduce(matches, vars)?;
         let theme = ThemeOptions::deduce(matches, vars)?;
 
 
-        Ok(Self { dir_action, filter, view, theme })
+        Ok(Self {
+            dir_action,
+            filter,
+            view,
+            theme,
+        })
     }
     }
 }
 }
 
 
-
 /// The result of the `Options::getopts` function.
 /// The result of the `Options::getopts` function.
 #[derive(Debug)]
 #[derive(Debug)]
 pub enum OptionsResult<'args> {
 pub enum OptionsResult<'args> {
-
     /// The options were parsed successfully.
     /// The options were parsed successfully.
     Ok(Options, Vec<&'args OsStr>),
     Ok(Options, Vec<&'args OsStr>),
 
 
@@ -210,7 +225,6 @@ pub enum OptionsResult<'args> {
     Version(VersionString),
     Version(VersionString),
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 pub mod test {
 pub mod test {
     use crate::options::parser::{Arg, MatchedFlags};
     use crate::options::parser::{Arg, MatchedFlags};
@@ -229,8 +243,14 @@ pub mod test {
     ///
     ///
     /// It returns a vector with one or two elements in.
     /// It returns a vector with one or two elements in.
     /// These elements can then be tested with `assert_eq` or what have you.
     /// These elements can then be tested with `assert_eq` or what have you.
-    pub fn parse_for_test<T, F>(inputs: &[&str], args: &'static [&'static Arg], strictnesses: Strictnesses, get: F) -> Vec<T>
-    where F: Fn(&MatchedFlags<'_>) -> T
+    pub fn parse_for_test<T, F>(
+        inputs: &[&str],
+        args: &'static [&'static Arg],
+        strictnesses: Strictnesses,
+        get: F,
+    ) -> Vec<T>
+    where
+        F: Fn(&MatchedFlags<'_>) -> T,
     {
     {
         use self::Strictnesses::*;
         use self::Strictnesses::*;
         use crate::options::parser::{Args, Strictness};
         use crate::options::parser::{Args, Strictness};

+ 136 - 117
src/options/parser.rs

@@ -27,12 +27,10 @@
 //! command-line options, as all the options and their values (such as
 //! command-line options, as all the options and their values (such as
 //! `--sort size`) are guaranteed to just be 8-bit ASCII.
 //! `--sort size`) are guaranteed to just be 8-bit ASCII.
 
 
-
 use std::ffi::{OsStr, OsString};
 use std::ffi::{OsStr, OsString};
 use std::fmt;
 use std::fmt;
 
 
-use crate::options::error::{OptionsError, Choices};
-
+use crate::options::error::{Choices, OptionsError};
 
 
 /// A **short argument** is a single ASCII character.
 /// A **short argument** is a single ASCII character.
 pub type ShortArg = u8;
 pub type ShortArg = u8;
@@ -61,8 +59,8 @@ pub enum Flag {
 impl Flag {
 impl Flag {
     pub fn matches(&self, arg: &Arg) -> bool {
     pub fn matches(&self, arg: &Arg) -> bool {
         match self {
         match self {
-            Self::Short(short)  => arg.short == Some(*short),
-            Self::Long(long)    => arg.long == *long,
+            Self::Short(short) => arg.short == Some(*short),
+            Self::Long(long) => arg.long == *long,
         }
         }
     }
     }
 }
 }
@@ -70,8 +68,8 @@ impl Flag {
 impl fmt::Display for Flag {
 impl fmt::Display for Flag {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
         match self {
         match self {
-            Self::Short(short)  => write!(f, "-{}", *short as char),
-            Self::Long(long)    => write!(f, "--{long}"),
+            Self::Short(short) => write!(f, "-{}", *short as char),
+            Self::Long(long) => write!(f, "--{long}"),
         }
         }
     }
     }
 }
 }
@@ -79,7 +77,6 @@ impl fmt::Display for Flag {
 /// Whether redundant arguments should be considered a problem.
 /// Whether redundant arguments should be considered a problem.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum Strictness {
 pub enum Strictness {
-
     /// Throw an error when an argument doesn’t do anything, either because
     /// Throw an error when an argument doesn’t do anything, either because
     /// it requires another argument to be specified, or because two conflict.
     /// it requires another argument to be specified, or because two conflict.
     ComplainAboutRedundantArguments,
     ComplainAboutRedundantArguments,
@@ -93,7 +90,6 @@ pub enum Strictness {
 /// arguments.
 /// arguments.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum TakesValue {
 pub enum TakesValue {
-
     /// This flag has to be followed by a value.
     /// This flag has to be followed by a value.
     /// If there’s a fixed set of possible values, they can be printed out
     /// If there’s a fixed set of possible values, they can be printed out
     /// with the error text.
     /// with the error text.
@@ -106,11 +102,9 @@ pub enum TakesValue {
     Optional(Option<Values>),
     Optional(Option<Values>),
 }
 }
 
 
-
 /// An **argument** can be matched by one of the user’s input strings.
 /// An **argument** can be matched by one of the user’s input strings.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub struct Arg {
 pub struct Arg {
-
     /// The short argument that matches it, if any.
     /// The short argument that matches it, if any.
     pub short: Option<ShortArg>,
     pub short: Option<ShortArg>,
 
 
@@ -134,17 +128,20 @@ impl fmt::Display for Arg {
     }
     }
 }
 }
 
 
-
 /// Literally just several args.
 /// Literally just several args.
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub struct Args(pub &'static [&'static Arg]);
 pub struct Args(pub &'static [&'static Arg]);
 
 
 impl Args {
 impl Args {
-
     /// Iterates over the given list of command-line arguments and parses
     /// Iterates over the given list of command-line arguments and parses
     /// them into a list of matched flags and free strings.
     /// 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>
+    pub fn parse<'args, I>(
+        &self,
+        inputs: I,
+        strictness: Strictness,
+    ) -> Result<Matches<'args>, ParseError>
+    where
+        I: IntoIterator<Item = &'args OsStr>,
     {
     {
         let mut parsing = true;
         let mut parsing = true;
 
 
@@ -163,13 +160,11 @@ impl Args {
             // This allows a file named “--arg” to be specified by passing in
             // This allows a file named “--arg” to be specified by passing in
             // the pair “-- --arg”, without it getting matched as a flag that
             // the pair “-- --arg”, without it getting matched as a flag that
             // doesn’t exist.
             // doesn’t exist.
-            if ! parsing {
+            if !parsing {
                 frees.push(arg);
                 frees.push(arg);
-            }
-            else if arg == "--" {
+            } else if arg == "--" {
                 parsing = false;
                 parsing = false;
             }
             }
-
             // If the string starts with *two* dashes then it’s a long argument.
             // If the string starts with *two* dashes then it’s a long argument.
             else if bytes.starts_with(b"--") {
             else if bytes.starts_with(b"--") {
                 let long_arg_name = bytes_to_os_str(&bytes[2..]);
                 let long_arg_name = bytes_to_os_str(&bytes[2..]);
@@ -181,12 +176,12 @@ impl Args {
                     let arg = self.lookup_long(before)?;
                     let arg = self.lookup_long(before)?;
                     let flag = Flag::Long(arg.long);
                     let flag = Flag::Long(arg.long);
                     match arg.takes_value {
                     match arg.takes_value {
-                        TakesValue::Necessary(_) |
-                        TakesValue::Optional(_)  => result_flags.push((flag, Some(after))),
-                        TakesValue::Forbidden    => return Err(ParseError::ForbiddenValue { flag }),
+                        TakesValue::Necessary(_) | TakesValue::Optional(_) => {
+                            result_flags.push((flag, Some(after)));
+                        }
+                        TakesValue::Forbidden => return Err(ParseError::ForbiddenValue { flag }),
                     }
                     }
                 }
                 }
-
                 // If there’s no equals, then the entire string (apart from
                 // If there’s no equals, then the entire string (apart from
                 // the dashes) is the argument name.
                 // the dashes) is the argument name.
                 else {
                 else {
@@ -199,23 +194,20 @@ impl Args {
                         TakesValue::Necessary(values) => {
                         TakesValue::Necessary(values) => {
                             if let Some(next_arg) = inputs.next() {
                             if let Some(next_arg) = inputs.next() {
                                 result_flags.push((flag, Some(next_arg)));
                                 result_flags.push((flag, Some(next_arg)));
-                            }
-                            else {
-                                return Err(ParseError::NeedsValue { flag, values })
+                            } else {
+                                return Err(ParseError::NeedsValue { flag, values });
                             }
                             }
                         }
                         }
                         TakesValue::Optional(_) => {
                         TakesValue::Optional(_) => {
                             if let Some(next_arg) = inputs.next() {
                             if let Some(next_arg) = inputs.next() {
                                 result_flags.push((flag, Some(next_arg)));
                                 result_flags.push((flag, Some(next_arg)));
-                            }
-                            else {
+                            } else {
                                 result_flags.push((flag, None));
                                 result_flags.push((flag, None));
                             }
                             }
                         }
                         }
                     }
                     }
                 }
                 }
             }
             }
-
             // If the string starts with *one* dash then it’s one or more
             // If the string starts with *one* dash then it’s one or more
             // short arguments.
             // short arguments.
             else if bytes.starts_with(b"-") && arg != "-" {
             else if bytes.starts_with(b"-") && arg != "-" {
@@ -234,15 +226,15 @@ impl Args {
                 // it’s an error if any of the first set of arguments actually
                 // it’s an error if any of the first set of arguments actually
                 // takes a value.
                 // takes a value.
                 if let Some((before, after)) = split_on_equals(short_arg) {
                 if let Some((before, after)) = split_on_equals(short_arg) {
-                    let (arg_with_value, other_args) = os_str_to_bytes(before).split_last().unwrap();
+                    let (arg_with_value, other_args) =
+                        os_str_to_bytes(before).split_last().unwrap();
 
 
                     // Process the characters immediately following the dash...
                     // Process the characters immediately following the dash...
                     for byte in other_args {
                     for byte in other_args {
                         let arg = self.lookup_short(*byte)?;
                         let arg = self.lookup_short(*byte)?;
                         let flag = Flag::Short(*byte);
                         let flag = Flag::Short(*byte);
                         match arg.takes_value {
                         match arg.takes_value {
-                            TakesValue::Forbidden |
-                            TakesValue::Optional(_)  => {
+                            TakesValue::Forbidden | TakesValue::Optional(_) => {
                                 result_flags.push((flag, None));
                                 result_flags.push((flag, None));
                             }
                             }
                             TakesValue::Necessary(values) => {
                             TakesValue::Necessary(values) => {
@@ -255,8 +247,7 @@ impl Args {
                     let arg = self.lookup_short(*arg_with_value)?;
                     let arg = self.lookup_short(*arg_with_value)?;
                     let flag = Flag::Short(arg.short.unwrap());
                     let flag = Flag::Short(arg.short.unwrap());
                     match arg.takes_value {
                     match arg.takes_value {
-                        TakesValue::Necessary(_) |
-                        TakesValue::Optional(_)  => {
+                        TakesValue::Necessary(_) | TakesValue::Optional(_) => {
                             result_flags.push((flag, Some(after)));
                             result_flags.push((flag, Some(after)));
                         }
                         }
                         TakesValue::Forbidden => {
                         TakesValue::Forbidden => {
@@ -264,7 +255,6 @@ impl Args {
                         }
                         }
                     }
                     }
                 }
                 }
-
                 // If there’s no equals, then every character is parsed as
                 // If there’s no equals, then every character is parsed as
                 // its own short argument. However, if any of the arguments
                 // its own short argument. However, if any of the arguments
                 // takes a value, then the *rest* of the string is used as
                 // takes a value, then the *rest* of the string is used as
@@ -285,17 +275,14 @@ impl Args {
                             TakesValue::Forbidden => {
                             TakesValue::Forbidden => {
                                 result_flags.push((flag, None));
                                 result_flags.push((flag, None));
                             }
                             }
-                            TakesValue::Necessary(values) |
-                            TakesValue::Optional(values) => {
+                            TakesValue::Necessary(values) | TakesValue::Optional(values) => {
                                 if index < bytes.len() - 1 {
                                 if index < bytes.len() - 1 {
-                                    let remnants = &bytes[index+1 ..];
+                                    let remnants = &bytes[index + 1..];
                                     result_flags.push((flag, Some(bytes_to_os_str(remnants))));
                                     result_flags.push((flag, Some(bytes_to_os_str(remnants))));
                                     break;
                                     break;
-                                }
-                                else if let Some(next_arg) = inputs.next() {
+                                } else if let Some(next_arg) = inputs.next() {
                                     result_flags.push((flag, Some(next_arg)));
                                     result_flags.push((flag, Some(next_arg)));
-                                }
-                                else {
+                                } else {
                                     match arg.takes_value {
                                     match arg.takes_value {
                                         TakesValue::Forbidden => {
                                         TakesValue::Forbidden => {
                                             unreachable!()
                                             unreachable!()
@@ -313,36 +300,41 @@ impl Args {
                     }
                     }
                 }
                 }
             }
             }
-
             // Otherwise, it’s a free string, usually a file name.
             // Otherwise, it’s a free string, usually a file name.
             else {
             else {
                 frees.push(arg);
                 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> {
     fn lookup_short(&self, short: ShortArg) -> Result<&Arg, ParseError> {
         match self.0.iter().find(|arg| arg.short == Some(short)) {
         match self.0.iter().find(|arg| arg.short == Some(short)) {
-            Some(arg)  => Ok(arg),
-            None       => Err(ParseError::UnknownShortArgument { attempt: short })
+            Some(arg) => Ok(arg),
+            None => Err(ParseError::UnknownShortArgument { attempt: short }),
         }
         }
     }
     }
 
 
     fn lookup_long(&self, long: &OsStr) -> Result<&Arg, ParseError> {
     fn lookup_long(&self, long: &OsStr) -> Result<&Arg, ParseError> {
         match self.0.iter().find(|arg| arg.long == long) {
         match self.0.iter().find(|arg| arg.long == long) {
-            Some(arg)  => Ok(arg),
-            None       => Err(ParseError::UnknownArgument { attempt: long.to_os_string() })
+            Some(arg) => Ok(arg),
+            None => Err(ParseError::UnknownArgument {
+                attempt: long.to_os_string(),
+            }),
         }
         }
     }
     }
 }
 }
 
 
-
 /// The **matches** are the result of parsing the user’s command-line strings.
 /// The **matches** are the result of parsing the user’s command-line strings.
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub struct Matches<'args> {
 pub struct Matches<'args> {
-
     /// The flags that were parsed from the user’s input.
     /// The flags that were parsed from the user’s input.
     pub flags: MatchedFlags<'args>,
     pub flags: MatchedFlags<'args>,
 
 
@@ -353,7 +345,6 @@ pub struct Matches<'args> {
 
 
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub struct MatchedFlags<'args> {
 pub struct MatchedFlags<'args> {
-
     /// The individual flags from the user’s input, in the order they were
     /// The individual flags from the user’s input, in the order they were
     /// originally given.
     /// originally given.
     ///
     ///
@@ -367,7 +358,6 @@ pub struct MatchedFlags<'args> {
 }
 }
 
 
 impl<'a> MatchedFlags<'a> {
 impl<'a> MatchedFlags<'a> {
-
     /// Whether the given argument was specified.
     /// Whether the given argument was specified.
     /// Returns `true` if it was, `false` if it wasn’t, and an error in
     /// Returns `true` if it was, `false` if it wasn’t, and an error in
     /// strict mode if it was specified more than once.
     /// strict mode if it was specified more than once.
@@ -382,16 +372,22 @@ impl<'a> MatchedFlags<'a> {
     ///
     ///
     /// You’ll have to test the resulting flag to see which argument it was.
     /// You’ll have to test the resulting flag to see which argument it was.
     pub fn has_where<P>(&self, predicate: P) -> Result<Option<&Flag>, OptionsError>
     pub fn has_where<P>(&self, predicate: P) -> Result<Option<&Flag>, OptionsError>
-    where P: Fn(&Flag) -> bool {
+    where
+        P: Fn(&Flag) -> bool,
+    {
         if self.is_strict() {
         if self.is_strict() {
-            let all = self.flags.iter()
-                          .filter(|tuple| tuple.1.is_none() && predicate(&tuple.0))
-                          .collect::<Vec<_>>();
-
-            if all.len() < 2 { Ok(all.first().map(|t| &t.0)) }
-                        else { Err(OptionsError::Duplicate(all[0].0, all[1].0)) }
-        }
-        else {
+            let all = self
+                .flags
+                .iter()
+                .filter(|tuple| tuple.1.is_none() && predicate(&tuple.0))
+                .collect::<Vec<_>>();
+
+            if all.len() < 2 {
+                Ok(all.first().map(|t| &t.0))
+            } else {
+                Err(OptionsError::Duplicate(all[0].0, all[1].0))
+            }
+        } else {
             Ok(self.has_where_any(predicate))
             Ok(self.has_where_any(predicate))
         }
         }
     }
     }
@@ -401,8 +397,12 @@ impl<'a> MatchedFlags<'a> {
     ///
     ///
     /// You’ll have to test the resulting flag to see which argument it was.
     /// You’ll have to test the resulting flag to see which argument it was.
     pub fn has_where_any<P>(&self, predicate: P) -> Option<&Flag>
     pub fn has_where_any<P>(&self, predicate: P) -> Option<&Flag>
-    where P: Fn(&Flag) -> bool {
-        self.flags.iter().rev()
+    where
+        P: Fn(&Flag) -> bool,
+    {
+        self.flags
+            .iter()
+            .rev()
             .find(|tuple| tuple.1.is_none() && predicate(&tuple.0))
             .find(|tuple| tuple.1.is_none() && predicate(&tuple.0))
             .map(|tuple| &tuple.0)
             .map(|tuple| &tuple.0)
     }
     }
@@ -424,19 +424,28 @@ impl<'a> MatchedFlags<'a> {
     ///
     ///
     /// It’s not possible to tell which flag the value belonged to from this.
     /// It’s not possible to tell which flag the value belonged to from this.
     pub fn get_where<P>(&self, predicate: P) -> Result<Option<&OsStr>, OptionsError>
     pub fn get_where<P>(&self, predicate: P) -> Result<Option<&OsStr>, OptionsError>
-    where P: Fn(&Flag) -> bool {
+    where
+        P: Fn(&Flag) -> bool,
+    {
         if self.is_strict() {
         if self.is_strict() {
-            let those = self.flags.iter()
-                            .filter(|tuple| tuple.1.is_some() && predicate(&tuple.0))
-                            .collect::<Vec<_>>();
-
-            if those.len() < 2 { Ok(those.first().copied().map(|t| t.1.unwrap())) }
-                          else { Err(OptionsError::Duplicate(those[0].0, those[1].0)) }
-        }
-        else {
-            let found = self.flags.iter().rev()
-                            .find(|tuple| tuple.1.is_some() && predicate(&tuple.0))
-                            .map(|tuple| tuple.1.unwrap());
+            let those = self
+                .flags
+                .iter()
+                .filter(|tuple| tuple.1.is_some() && predicate(&tuple.0))
+                .collect::<Vec<_>>();
+
+            if those.len() < 2 {
+                Ok(those.first().copied().map(|t| t.1.unwrap()))
+            } else {
+                Err(OptionsError::Duplicate(those[0].0, those[1].0))
+            }
+        } else {
+            let found = self
+                .flags
+                .iter()
+                .rev()
+                .find(|tuple| tuple.1.is_some() && predicate(&tuple.0))
+                .map(|tuple| tuple.1.unwrap());
             Ok(found)
             Ok(found)
         }
         }
     }
     }
@@ -447,7 +456,8 @@ impl<'a> MatchedFlags<'a> {
     /// Counts the number of occurrences of the given argument, even in
     /// Counts the number of occurrences of the given argument, even in
     /// strict mode.
     /// strict mode.
     pub fn count(&self, arg: &Arg) -> usize {
     pub fn count(&self, arg: &Arg) -> usize {
-        self.flags.iter()
+        self.flags
+            .iter()
             .filter(|tuple| tuple.0.matches(arg))
             .filter(|tuple| tuple.0.matches(arg))
             .count()
             .count()
     }
     }
@@ -459,12 +469,10 @@ impl<'a> MatchedFlags<'a> {
     }
     }
 }
 }
 
 
-
 /// A problem with the user’s input that meant it couldn’t be parsed into a
 /// A problem with the user’s input that meant it couldn’t be parsed into a
 /// coherent list of arguments.
 /// coherent list of arguments.
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub enum ParseError {
 pub enum ParseError {
-
     /// A flag that has to take a value was not given one.
     /// A flag that has to take a value was not given one.
     NeedsValue { flag: Flag, values: Option<Values> },
     NeedsValue { flag: Flag, values: Option<Values> },
 
 
@@ -484,36 +492,43 @@ pub enum ParseError {
 impl fmt::Display for ParseError {
 impl fmt::Display for ParseError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
         match self {
-            Self::NeedsValue { flag, values: None }      => write!(f, "Flag {flag} needs a value"),
-            Self::NeedsValue { flag, values: Some(cs) }  => write!(f, "Flag {flag} needs a value ({})", Choices(cs)),
-            Self::ForbiddenValue { flag }                => write!(f, "Flag {flag} cannot take a value"),
-            Self::UnknownShortArgument { attempt }       => write!(f, "Unknown argument -{}", *attempt as char),
-            Self::UnknownArgument { attempt }            => write!(f, "Unknown argument --{}", attempt.to_string_lossy()),
+            Self::NeedsValue { flag, values: None } => write!(f, "Flag {flag} needs a value"),
+            Self::NeedsValue {
+                flag,
+                values: Some(cs),
+            } => write!(f, "Flag {flag} needs a value ({})", Choices(cs)),
+            Self::ForbiddenValue { flag } => write!(f, "Flag {flag} cannot take a value"),
+            Self::UnknownShortArgument { attempt } => {
+                write!(f, "Unknown argument -{}", *attempt as char)
+            }
+            Self::UnknownArgument { attempt } => {
+                write!(f, "Unknown argument --{}", attempt.to_string_lossy())
+            }
         }
         }
     }
     }
 }
 }
 
 
 #[cfg(unix)]
 #[cfg(unix)]
-fn os_str_to_bytes(s: &OsStr) -> &[u8]{
+fn os_str_to_bytes(s: &OsStr) -> &[u8] {
     use std::os::unix::ffi::OsStrExt;
     use std::os::unix::ffi::OsStrExt;
 
 
-    return s.as_bytes()
+    return s.as_bytes();
 }
 }
 
 
 #[cfg(unix)]
 #[cfg(unix)]
-fn bytes_to_os_str(b: &[u8]) -> &OsStr{
+fn bytes_to_os_str(b: &[u8]) -> &OsStr {
     use std::os::unix::ffi::OsStrExt;
     use std::os::unix::ffi::OsStrExt;
 
 
     return OsStr::from_bytes(b);
     return OsStr::from_bytes(b);
 }
 }
 
 
 #[cfg(windows)]
 #[cfg(windows)]
-fn os_str_to_bytes(s: &OsStr) ->  &[u8]{
-    return s.to_str().unwrap().as_bytes()
+fn os_str_to_bytes(s: &OsStr) -> &[u8] {
+    return s.to_str().unwrap().as_bytes();
 }
 }
 
 
 #[cfg(windows)]
 #[cfg(windows)]
-fn bytes_to_os_str(b:  &[u8]) ->  &OsStr{
+fn bytes_to_os_str(b: &[u8]) -> &OsStr {
     use std::str;
     use std::str;
 
 
     return OsStr::new(str::from_utf8(b).unwrap());
     return OsStr::new(str::from_utf8(b).unwrap());
@@ -526,16 +541,14 @@ fn split_on_equals(input: &OsStr) -> Option<(&OsStr, &OsStr)> {
         let (before, after) = os_str_to_bytes(input).split_at(index);
         let (before, after) = os_str_to_bytes(input).split_at(index);
 
 
         // The after string contains the = that we need to remove.
         // The after string contains the = that we need to remove.
-        if ! before.is_empty() && after.len() >= 2 {
-            return Some((bytes_to_os_str(before),
-                         bytes_to_os_str(&after[1..])))
+        if !before.is_empty() && after.len() >= 2 {
+            return Some((bytes_to_os_str(before), bytes_to_os_str(&after[1..])));
         }
         }
     }
     }
 
 
     None
     None
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod split_test {
 mod split_test {
     use super::split_on_equals;
     use super::split_on_equals;
@@ -545,16 +558,17 @@ mod split_test {
         ($name:ident: $input:expr => None) => {
         ($name:ident: $input:expr => None) => {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                assert_eq!(split_on_equals(&OsString::from($input)),
-                           None);
+                assert_eq!(split_on_equals(&OsString::from($input)), None);
             }
             }
         };
         };
 
 
         ($name:ident: $input:expr => $before:expr, $after:expr) => {
         ($name:ident: $input:expr => $before:expr, $after:expr) => {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                assert_eq!(split_on_equals(&OsString::from($input)),
-                           Some((OsStr::new($before), OsStr::new($after))));
+                assert_eq!(
+                    split_on_equals(&OsString::from($input)),
+                    Some((OsStr::new($before), OsStr::new($after)))
+                );
             }
             }
         };
         };
     }
     }
@@ -571,7 +585,6 @@ mod split_test {
     test_split!(more: "this=that=other" => "this",   "that=other");
     test_split!(more: "this=that=other" => "this",   "that=other");
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod parse_test {
 mod parse_test {
     use super::*;
     use super::*;
@@ -580,16 +593,15 @@ mod parse_test {
         ($name:ident: $inputs:expr => frees: $frees:expr, flags: $flags:expr) => {
         ($name:ident: $inputs:expr => frees: $frees:expr, flags: $flags:expr) => {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-
                 let inputs: &[&'static str] = $inputs.as_ref();
                 let inputs: &[&'static str] = $inputs.as_ref();
                 let inputs = inputs.iter().map(OsStr::new);
                 let inputs = inputs.iter().map(OsStr::new);
 
 
                 let frees: &[&'static str] = $frees.as_ref();
                 let frees: &[&'static str] = $frees.as_ref();
-                let frees  = frees.iter().map(OsStr::new).collect();
+                let frees = frees.iter().map(OsStr::new).collect();
 
 
                 let flags = <[_]>::into_vec(Box::new($flags));
                 let flags = <[_]>::into_vec(Box::new($flags));
 
 
-                let strictness = Strictness::UseLastArguments;  // this isn’t even used
+                let strictness = Strictness::UseLastArguments; // this isn’t even used
                 let got = Args(TEST_ARGS).parse(inputs, strictness);
                 let got = Args(TEST_ARGS).parse(inputs, strictness);
                 let flags = MatchedFlags { flags, strictness };
                 let flags = MatchedFlags { flags, strictness };
 
 
@@ -605,15 +617,16 @@ mod parse_test {
 
 
                 let inputs = $inputs.iter().map(OsStr::new);
                 let inputs = $inputs.iter().map(OsStr::new);
 
 
-                let strictness = Strictness::UseLastArguments;  // this isn’t even used
+                let strictness = Strictness::UseLastArguments; // this isn’t even used
                 let got = Args(TEST_ARGS).parse(inputs, strictness);
                 let got = Args(TEST_ARGS).parse(inputs, strictness);
                 assert_eq!(got, Err($error));
                 assert_eq!(got, Err($error));
             }
             }
         };
         };
     }
     }
 
 
-    const SUGGESTIONS: Values = &[ "example" ];
+    const SUGGESTIONS: Values = &["example"];
 
 
+    #[rustfmt::skip]
     static TEST_ARGS: &[&Arg] = &[
     static TEST_ARGS: &[&Arg] = &[
         &Arg { short: Some(b'l'), long: "long",     takes_value: TakesValue::Forbidden },
         &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'v'), long: "verbose",  takes_value: TakesValue::Forbidden },
@@ -621,7 +634,6 @@ mod parse_test {
         &Arg { short: Some(b't'), long: "type",     takes_value: TakesValue::Necessary(Some(SUGGESTIONS)) }
         &Arg { short: Some(b't'), long: "type",     takes_value: TakesValue::Necessary(Some(SUGGESTIONS)) }
     ];
     ];
 
 
-
     // Just filenames
     // Just filenames
     test!(empty:       []       => frees: [],         flags: []);
     test!(empty:       []       => frees: [],         flags: []);
     test!(one_arg:     ["exa"]  => frees: [ "exa" ],  flags: []);
     test!(one_arg:     ["exa"]  => frees: [ "exa" ],  flags: []);
@@ -633,7 +645,6 @@ mod parse_test {
     test!(two_arg_l:   ["--", "--long"]  => frees: [ "--long" ],  flags: []);
     test!(two_arg_l:   ["--", "--long"]  => frees: [ "--long" ],  flags: []);
     test!(two_arg_s:   ["--", "-l"]      => frees: [ "-l" ],      flags: []);
     test!(two_arg_s:   ["--", "-l"]      => frees: [ "-l" ],      flags: []);
 
 
-
     // Long args
     // Long args
     test!(long:        ["--long"]               => frees: [],       flags: [ (Flag::Long("long"), None) ]);
     test!(long:        ["--long"]               => frees: [],       flags: [ (Flag::Long("long"), None) ]);
     test!(long_then:   ["--long", "4"]          => frees: [ "4" ],  flags: [ (Flag::Long("long"), None) ]);
     test!(long_then:   ["--long", "4"]          => frees: [ "4" ],  flags: [ (Flag::Long("long"), None) ]);
@@ -650,7 +661,6 @@ mod parse_test {
     test!(arg_equals_s:  ["--type=exa"]     => frees: [],  flags: [ (Flag::Long("type"), Some(OsStr::new("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"))) ]);
     test!(arg_then_s:    ["--type", "exa"]  => frees: [],  flags: [ (Flag::Long("type"), Some(OsStr::new("exa"))) ]);
 
 
-
     // Short args
     // Short args
     test!(short:       ["-l"]            => frees: [],       flags: [ (Flag::Short(b'l'), None) ]);
     test!(short:       ["-l"]            => frees: [],       flags: [ (Flag::Short(b'l'), None) ]);
     test!(short_then:  ["-l", "4"]       => frees: [ "4" ],  flags: [ (Flag::Short(b'l'), None) ]);
     test!(short_then:  ["-l", "4"]       => frees: [ "4" ],  flags: [ (Flag::Short(b'l'), None) ]);
@@ -672,7 +682,6 @@ mod parse_test {
     test!(short_two_equals_s:   ["-t=exa"]     => 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"))) ]);
     test!(short_two_next_s:     ["-t", "exa"]  => frees: [],  flags: [(Flag::Short(b't'), Some(OsStr::new("exa"))) ]);
 
 
-
     // Unknown args
     // Unknown args
     test!(unknown_long:          ["--quiet"]      => error UnknownArgument      { attempt: OsString::from("quiet") });
     test!(unknown_long:          ["--quiet"]      => error UnknownArgument      { attempt: OsString::from("quiet") });
     test!(unknown_long_eq:       ["--quiet=shhh"] => error UnknownArgument      { attempt: OsString::from("quiet") });
     test!(unknown_long_eq:       ["--quiet=shhh"] => error UnknownArgument      { attempt: OsString::from("quiet") });
@@ -682,7 +691,6 @@ mod parse_test {
     test!(unknown_short_2nd_eq:  ["-lq=shhh"]     => error UnknownShortArgument { attempt: b'q' });
     test!(unknown_short_2nd_eq:  ["-lq=shhh"]     => error UnknownShortArgument { attempt: b'q' });
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod matches_test {
 mod matches_test {
     use super::*;
     use super::*;
@@ -701,9 +709,16 @@ 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_never:  [],                                                              has VERBOSE => false);
     test!(short_once:   [(Flag::Short(b'v'), None)],                                     has VERBOSE => true);
     test!(short_once:   [(Flag::Short(b'v'), None)],                                     has VERBOSE => true);
@@ -712,13 +727,12 @@ mod matches_test {
     test!(long_twice:   [(Flag::Long("verbose"), None), (Flag::Long("verbose"), None)],  has VERBOSE => true);
     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!(long_mixed:   [(Flag::Long("verbose"), None), (Flag::Short(b'v'), None)],      has VERBOSE => true);
 
 
-
     #[test]
     #[test]
     fn only_count() {
     fn only_count() {
         let everything = OsString::from("everything");
         let everything = OsString::from("everything");
 
 
         let flags = MatchedFlags {
         let flags = MatchedFlags {
-            flags: vec![ (Flag::Short(b'c'), Some(&*everything)) ],
+            flags: vec![(Flag::Short(b'c'), Some(&*everything))],
             strictness: Strictness::UseLastArguments,
             strictness: Strictness::UseLastArguments,
         };
         };
 
 
@@ -728,11 +742,13 @@ mod matches_test {
     #[test]
     #[test]
     fn rightmost_count() {
     fn rightmost_count() {
         let everything = OsString::from("everything");
         let everything = OsString::from("everything");
-        let nothing    = OsString::from("nothing");
+        let nothing = OsString::from("nothing");
 
 
         let flags = MatchedFlags {
         let flags = MatchedFlags {
-            flags: vec![ (Flag::Short(b'c'), Some(&*everything)),
-                         (Flag::Short(b'c'), Some(&*nothing)) ],
+            flags: vec![
+                (Flag::Short(b'c'), Some(&*everything)),
+                (Flag::Short(b'c'), Some(&*nothing)),
+            ],
             strictness: Strictness::UseLastArguments,
             strictness: Strictness::UseLastArguments,
         };
         };
 
 
@@ -741,7 +757,10 @@ mod matches_test {
 
 
     #[test]
     #[test]
     fn no_count() {
     fn no_count() {
-        let flags = MatchedFlags { flags: Vec::new(), strictness: Strictness::UseLastArguments };
+        let flags = MatchedFlags {
+            flags: Vec::new(),
+            strictness: Strictness::UseLastArguments,
+        };
 
 
         assert!(!flags.has(&COUNT).unwrap());
         assert!(!flags.has(&COUNT).unwrap());
     }
     }

+ 53 - 42
src/options/theme.rs

@@ -1,7 +1,6 @@
-use crate::options::{flags, vars, Vars, OptionsError};
 use crate::options::parser::MatchedFlags;
 use crate::options::parser::MatchedFlags;
-use crate::theme::{Options, UseColours, ColourScale, Definitions};
-
+use crate::options::{flags, vars, OptionsError, Vars};
+use crate::theme::{ColourScale, Definitions, Options, UseColours};
 
 
 impl Options {
 impl Options {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
@@ -9,17 +8,19 @@ impl Options {
         let colour_scale = ColourScale::deduce(matches)?;
         let colour_scale = ColourScale::deduce(matches)?;
 
 
         let definitions = if use_colours == UseColours::Never {
         let definitions = if use_colours == UseColours::Never {
-                Definitions::default()
-            }
-            else {
-                Definitions::deduce(vars)
-            };
+            Definitions::default()
+        } else {
+            Definitions::deduce(vars)
+        };
 
 
-        Ok(Self { use_colours, colour_scale, definitions })
+        Ok(Self {
+            use_colours,
+            colour_scale,
+            definitions,
+        })
     }
     }
 }
 }
 
 
-
 impl UseColours {
 impl UseColours {
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
         let default_value = match vars.get(vars::NO_COLOR) {
         let default_value = match vars.get(vars::NO_COLOR) {
@@ -27,65 +28,73 @@ impl UseColours {
             None => Self::Automatic,
             None => Self::Automatic,
         };
         };
 
 
-        let Some(word) = matches.get_where(|f| f.matches(&flags::COLOR) || f.matches(&flags::COLOUR))? else { return Ok(default_value) };
+        let Some(word) =
+            matches.get_where(|f| f.matches(&flags::COLOR) || f.matches(&flags::COLOUR))?
+        else {
+            return Ok(default_value);
+        };
 
 
         if word == "always" {
         if word == "always" {
             Ok(Self::Always)
             Ok(Self::Always)
-        }
-        else if word == "auto" || word == "automatic" {
+        } else if word == "auto" || word == "automatic" {
             Ok(Self::Automatic)
             Ok(Self::Automatic)
-        }
-        else if word == "never" {
+        } else if word == "never" {
             Ok(Self::Never)
             Ok(Self::Never)
-        }
-        else {
+        } else {
             Err(OptionsError::BadArgument(&flags::COLOR, word.into()))
             Err(OptionsError::BadArgument(&flags::COLOR, word.into()))
         }
         }
     }
     }
 }
 }
 
 
-
 impl ColourScale {
 impl ColourScale {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
-        if matches.has_where(|f| f.matches(&flags::COLOR_SCALE) || f.matches(&flags::COLOUR_SCALE))?.is_some() {
+        if matches
+            .has_where(|f| f.matches(&flags::COLOR_SCALE) || f.matches(&flags::COLOUR_SCALE))?
+            .is_some()
+        {
             Ok(Self::Gradient)
             Ok(Self::Gradient)
-        }
-        else {
+        } else {
             Ok(Self::Fixed)
             Ok(Self::Fixed)
         }
         }
     }
     }
 }
 }
 
 
-
 impl Definitions {
 impl Definitions {
     fn deduce<V: Vars>(vars: &V) -> Self {
     fn deduce<V: Vars>(vars: &V) -> Self {
-        let ls =  vars.get(vars::LS_COLORS)
+        let ls = vars
+            .get(vars::LS_COLORS)
             .map(|e| e.to_string_lossy().to_string());
             .map(|e| e.to_string_lossy().to_string());
-        let exa = vars.get_with_fallback(vars::EZA_COLORS, vars::EXA_COLORS)
+        let exa = vars
+            .get_with_fallback(vars::EZA_COLORS, vars::EXA_COLORS)
             .map(|e| e.to_string_lossy().to_string());
             .map(|e| e.to_string_lossy().to_string());
         Self { ls, exa }
         Self { ls, exa }
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod terminal_test {
 mod terminal_test {
     use super::*;
     use super::*;
-    use std::ffi::OsString;
     use crate::options::flags;
     use crate::options::flags;
-    use crate::options::parser::{Flag, Arg};
+    use crate::options::parser::{Arg, Flag};
+    use std::ffi::OsString;
 
 
     use crate::options::test::parse_for_test;
     use crate::options::test::parse_for_test;
     use crate::options::test::Strictnesses::*;
     use crate::options::test::Strictnesses::*;
 
 
-    static TEST_ARGS: &[&Arg] = &[ &flags::COLOR,       &flags::COLOUR,
-                                   &flags::COLOR_SCALE, &flags::COLOUR_SCALE, ];
+    static TEST_ARGS: &[&Arg] = &[
+        &flags::COLOR,
+        &flags::COLOUR,
+        &flags::COLOR_SCALE,
+        &flags::COLOUR_SCALE,
+    ];
 
 
     macro_rules! test {
     macro_rules! test {
         ($name:ident:  $type:ident <- $inputs:expr;  $stricts:expr => $result:expr) => {
         ($name:ident:  $type:ident <- $inputs:expr;  $stricts:expr => $result:expr) => {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf)
+                }) {
                     assert_eq!(result, $result);
                     assert_eq!(result, $result);
                 }
                 }
             }
             }
@@ -95,7 +104,9 @@ mod terminal_test {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
                 let env = $env;
                 let env = $env;
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &env)) {
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf, &env)
+                }) {
                     assert_eq!(result, $result);
                     assert_eq!(result, $result);
                 }
                 }
             }
             }
@@ -104,7 +115,9 @@ mod terminal_test {
         ($name:ident:  $type:ident <- $inputs:expr;  $stricts:expr => err $result:expr) => {
         ($name:ident:  $type:ident <- $inputs:expr;  $stricts:expr => err $result:expr) => {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf)
+                }) {
                     assert_eq!(result.unwrap_err(), $result);
                     assert_eq!(result.unwrap_err(), $result);
                 }
                 }
             }
             }
@@ -114,7 +127,9 @@ mod terminal_test {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
                 let env = $env;
                 let env = $env;
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &env)) {
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf, &env)
+                }) {
                     assert_eq!(result.unwrap_err(), $result);
                     assert_eq!(result.unwrap_err(), $result);
                 }
                 }
             }
             }
@@ -147,23 +162,19 @@ mod terminal_test {
     // Test impl that just returns the value it has.
     // Test impl that just returns the value it has.
     impl Vars for MockVars {
     impl Vars for MockVars {
         fn get(&self, name: &'static str) -> Option<OsString> {
         fn get(&self, name: &'static str) -> Option<OsString> {
-            if name == vars::LS_COLORS && ! self.ls.is_empty() {
+            if name == vars::LS_COLORS && !self.ls.is_empty() {
                 Some(OsString::from(self.ls))
                 Some(OsString::from(self.ls))
-            }
-            else if (name == vars::EZA_COLORS || name == vars::EXA_COLORS) && ! self.exa.is_empty() {
+            } else if (name == vars::EZA_COLORS || name == vars::EXA_COLORS) && !self.exa.is_empty()
+            {
                 Some(OsString::from(self.exa))
                 Some(OsString::from(self.exa))
-            }
-            else if name == vars::NO_COLOR && ! self.no_color.is_empty() {
+            } else if name == vars::NO_COLOR && !self.no_color.is_empty() {
                 Some(OsString::from(self.no_color))
                 Some(OsString::from(self.no_color))
-            }
-            else {
+            } else {
                 None
                 None
             }
             }
         }
         }
     }
     }
 
 
-
-
     // Default
     // Default
     test!(empty:         UseColours <- [], MockVars::empty();                     Both => Ok(UseColours::Automatic));
     test!(empty:         UseColours <- [], MockVars::empty();                     Both => Ok(UseColours::Automatic));
     test!(empty_with_no_color: UseColours <- [], MockVars::with_no_color();             Both => Ok(UseColours::Never));
     test!(empty_with_no_color: UseColours <- [], MockVars::with_no_color();             Both => Ok(UseColours::Never));

+ 1 - 4
src/options/vars.rs

@@ -1,6 +1,5 @@
 use std::ffi::OsString;
 use std::ffi::OsString;
 
 
-
 // General variables
 // General variables
 
 
 /// Environment variable used to colour files, both by their filesystem type
 /// Environment variable used to colour files, both by their filesystem type
@@ -53,7 +52,6 @@ pub static EZA_GRID_ROWS: &str = "EZA_GRID_ROWS";
 pub static EXA_ICON_SPACING: &str = "EXA_ICON_SPACING";
 pub static EXA_ICON_SPACING: &str = "EXA_ICON_SPACING";
 pub static EZA_ICON_SPACING: &str = "EZA_ICON_SPACING";
 pub static EZA_ICON_SPACING: &str = "EZA_ICON_SPACING";
 
 
-
 /// Mockable wrapper for `std::env::var_os`.
 /// Mockable wrapper for `std::env::var_os`.
 pub trait Vars {
 pub trait Vars {
     fn get(&self, name: &'static str) -> Option<OsString>;
     fn get(&self, name: &'static str) -> Option<OsString>;
@@ -69,12 +67,11 @@ pub trait Vars {
     fn source(&self, name: &'static str, fallback: &'static str) -> Option<&'static str> {
     fn source(&self, name: &'static str, fallback: &'static str) -> Option<&'static str> {
         match self.get(name) {
         match self.get(name) {
             Some(_) => Some(name),
             Some(_) => Some(name),
-            None    => self.get(fallback).and(Some(fallback)),
+            None => self.get(fallback).and(Some(fallback)),
         }
         }
     }
     }
 }
 }
 
 
-
 // Test impl that just returns the value it has.
 // Test impl that just returns the value it has.
 #[cfg(test)]
 #[cfg(test)]
 impl Vars for Option<OsString> {
 impl Vars for Option<OsString> {

+ 8 - 8
src/options/version.rs

@@ -7,13 +7,11 @@ use std::fmt;
 use crate::options::flags;
 use crate::options::flags;
 use crate::options::parser::MatchedFlags;
 use crate::options::parser::MatchedFlags;
 
 
-
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub struct VersionString;
 pub struct VersionString;
 // There were options here once, but there aren’t anymore!
 // There were options here once, but there aren’t anymore!
 
 
 impl VersionString {
 impl VersionString {
-
     /// Determines how to show the version, if at all, based on the user’s
     /// Determines how to show the version, if at all, based on the user’s
     /// command-line arguments. This one works backwards from the other
     /// command-line arguments. This one works backwards from the other
     /// ‘deduce’ functions, returning Err if help needs to be shown.
     /// ‘deduce’ functions, returning Err if help needs to be shown.
@@ -22,8 +20,7 @@ impl VersionString {
     pub fn deduce(matches: &MatchedFlags<'_>) -> Option<Self> {
     pub fn deduce(matches: &MatchedFlags<'_>) -> Option<Self> {
         if matches.count(&flags::VERSION) > 0 {
         if matches.count(&flags::VERSION) > 0 {
             Some(Self)
             Some(Self)
-        }
-        else {
+        } else {
             None
             None
         }
         }
     }
     }
@@ -31,11 +28,14 @@ impl VersionString {
 
 
 impl fmt::Display for VersionString {
 impl fmt::Display for VersionString {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
-        write!(f, "{}", include_str!(concat!(env!("OUT_DIR"), "/version_string.txt")))
+        write!(
+            f,
+            "{}",
+            include_str!(concat!(env!("OUT_DIR"), "/version_string.txt"))
+        )
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod test {
 mod test {
     use crate::options::{Options, OptionsResult};
     use crate::options::{Options, OptionsResult};
@@ -43,14 +43,14 @@ mod test {
 
 
     #[test]
     #[test]
     fn version() {
     fn version() {
-        let args = vec![ OsStr::new("--version") ];
+        let args = vec![OsStr::new("--version")];
         let opts = Options::parse(args, &None);
         let opts = Options::parse(args, &None);
         assert!(matches!(opts, OptionsResult::Version(_)));
         assert!(matches!(opts, OptionsResult::Version(_)));
     }
     }
 
 
     #[test]
     #[test]
     fn version_with_file() {
     fn version_with_file() {
-        let args = vec![ OsStr::new("--version"), OsStr::new("me") ];
+        let args = vec![OsStr::new("--version"), OsStr::new("me")];
         let opts = Options::parse(args, &None);
         let opts = Options::parse(args, &None);
         assert!(matches!(opts, OptionsResult::Version(_)));
         assert!(matches!(opts, OptionsResult::Version(_)));
     }
     }

+ 176 - 128
src/options/view.rs

@@ -1,12 +1,11 @@
 use crate::fs::feature::xattr;
 use crate::fs::feature::xattr;
-use crate::options::{flags, OptionsError, NumberSource, Vars};
 use crate::options::parser::MatchedFlags;
 use crate::options::parser::MatchedFlags;
-use crate::output::{View, Mode, TerminalWidth, grid, details};
-use crate::output::grid_details::{self, RowThreshold};
+use crate::options::{flags, NumberSource, OptionsError, Vars};
 use crate::output::file_name::Options as FileStyle;
 use crate::output::file_name::Options as FileStyle;
-use crate::output::table::{TimeTypes, SizeFormat, UserFormat, Columns, Options as TableOptions};
+use crate::output::grid_details::{self, RowThreshold};
+use crate::output::table::{Columns, Options as TableOptions, SizeFormat, TimeTypes, UserFormat};
 use crate::output::time::TimeFormat;
 use crate::output::time::TimeFormat;
-
+use crate::output::{details, grid, Mode, TerminalWidth, View};
 
 
 impl View {
 impl View {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
@@ -14,13 +13,16 @@ impl View {
         let width = TerminalWidth::deduce(matches, vars)?;
         let width = TerminalWidth::deduce(matches, vars)?;
         let file_style = FileStyle::deduce(matches, vars)?;
         let file_style = FileStyle::deduce(matches, vars)?;
         let deref_links = matches.has(&flags::DEREF_LINKS)?;
         let deref_links = matches.has(&flags::DEREF_LINKS)?;
-        Ok(Self { mode, width, file_style, deref_links })
+        Ok(Self {
+            mode,
+            width,
+            file_style,
+            deref_links,
+        })
     }
     }
 }
 }
 
 
-
 impl Mode {
 impl Mode {
-
     /// Determine which viewing mode to use based on the user’s options.
     /// Determine which viewing mode to use based on the user’s options.
     ///
     ///
     /// As with the other options, arguments are scanned right-to-left and the
     /// As with the other options, arguments are scanned right-to-left and the
@@ -30,8 +32,12 @@ impl Mode {
     /// This is complicated a little by the fact that `--grid` and `--tree`
     /// This is complicated a little by the fact that `--grid` and `--tree`
     /// can also combine with `--long`, so care has to be taken to use the
     /// can also combine with `--long`, so care has to be taken to use the
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
-        let flag = matches.has_where_any(|f| f.matches(&flags::LONG) || f.matches(&flags::ONE_LINE)
-                                          || f.matches(&flags::GRID) || f.matches(&flags::TREE));
+        let flag = matches.has_where_any(|f| {
+            f.matches(&flags::LONG)
+                || f.matches(&flags::ONE_LINE)
+                || f.matches(&flags::GRID)
+                || f.matches(&flags::TREE)
+        });
 
 
         let Some(flag) = flag else {
         let Some(flag) = flag else {
             Self::strict_check_long_flags(matches)?;
             Self::strict_check_long_flags(matches)?;
@@ -40,19 +46,24 @@ impl Mode {
         };
         };
 
 
         if flag.matches(&flags::LONG)
         if flag.matches(&flags::LONG)
-        || (flag.matches(&flags::TREE) && matches.has(&flags::LONG)?)
-        || (flag.matches(&flags::GRID) && matches.has(&flags::LONG)?)
+            || (flag.matches(&flags::TREE) && matches.has(&flags::LONG)?)
+            || (flag.matches(&flags::GRID) && matches.has(&flags::LONG)?)
         {
         {
             let _ = matches.has(&flags::LONG)?;
             let _ = matches.has(&flags::LONG)?;
             let details = details::Options::deduce_long(matches, vars)?;
             let details = details::Options::deduce_long(matches, vars)?;
 
 
-            let flag = matches.has_where_any(|f| f.matches(&flags::GRID) || f.matches(&flags::TREE));
+            let flag =
+                matches.has_where_any(|f| f.matches(&flags::GRID) || f.matches(&flags::TREE));
 
 
             if flag.is_some() && flag.unwrap().matches(&flags::GRID) {
             if flag.is_some() && flag.unwrap().matches(&flags::GRID) {
                 let _ = matches.has(&flags::GRID)?;
                 let _ = matches.has(&flags::GRID)?;
                 let grid = grid::Options::deduce(matches)?;
                 let grid = grid::Options::deduce(matches)?;
                 let row_threshold = RowThreshold::deduce(vars)?;
                 let row_threshold = RowThreshold::deduce(vars)?;
-                let grid_details = grid_details::Options { grid, details, row_threshold };
+                let grid_details = grid_details::Options {
+                    grid,
+                    details,
+                    row_threshold,
+                };
                 return Ok(Self::GridDetails(grid_details));
                 return Ok(Self::GridDetails(grid_details));
             }
             }
 
 
@@ -81,9 +92,18 @@ impl Mode {
         // If --long hasn’t been passed, then check if we need to warn the
         // If --long hasn’t been passed, then check if we need to warn the
         // user about flags that won’t have any effect.
         // user about flags that won’t have any effect.
         if matches.is_strict() {
         if matches.is_strict() {
-            for option in &[ &flags::BINARY, &flags::BYTES, &flags::INODE, &flags::LINKS,
-                             &flags::HEADER, &flags::BLOCKSIZE, &flags::TIME, &flags::GROUP, &flags::NUMERIC,
-                             &flags::MOUNTS ] {
+            for option in &[
+                &flags::BINARY,
+                &flags::BYTES,
+                &flags::INODE,
+                &flags::LINKS,
+                &flags::HEADER,
+                &flags::BLOCKSIZE,
+                &flags::TIME,
+                &flags::GROUP,
+                &flags::NUMERIC,
+                &flags::MOUNTS,
+            ] {
                 if matches.has(option)? {
                 if matches.has(option)? {
                     return Err(OptionsError::Useless(option, false, &flags::LONG));
                     return Err(OptionsError::Useless(option, false, &flags::LONG));
                 }
                 }
@@ -91,9 +111,15 @@ impl Mode {
 
 
             if matches.has(&flags::GIT)? && !matches.has(&flags::NO_GIT)? {
             if matches.has(&flags::GIT)? && !matches.has(&flags::NO_GIT)? {
                 return Err(OptionsError::Useless(&flags::GIT, false, &flags::LONG));
                 return Err(OptionsError::Useless(&flags::GIT, false, &flags::LONG));
-            }
-            else if matches.has(&flags::LEVEL)? && ! matches.has(&flags::RECURSE)? && ! matches.has(&flags::TREE)? {
-                return Err(OptionsError::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE));
+            } else if matches.has(&flags::LEVEL)?
+                && !matches.has(&flags::RECURSE)?
+                && !matches.has(&flags::TREE)?
+            {
+                return Err(OptionsError::Useless2(
+                    &flags::LEVEL,
+                    &flags::RECURSE,
+                    &flags::TREE,
+                ));
             }
             }
         }
         }
 
 
@@ -101,7 +127,6 @@ impl Mode {
     }
     }
 }
 }
 
 
-
 impl grid::Options {
 impl grid::Options {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
         let grid = grid::Options {
         let grid = grid::Options {
@@ -112,7 +137,6 @@ impl grid::Options {
     }
     }
 }
 }
 
 
-
 impl details::Options {
 impl details::Options {
     fn deduce_tree(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     fn deduce_tree(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
         let details = details::Options {
         let details = details::Options {
@@ -128,10 +152,9 @@ impl details::Options {
 
 
     fn deduce_long<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     fn deduce_long<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
         if matches.is_strict() {
         if matches.is_strict() {
-            if matches.has(&flags::ACROSS)? && ! matches.has(&flags::GRID)? {
+            if matches.has(&flags::ACROSS)? && !matches.has(&flags::GRID)? {
                 return Err(OptionsError::Useless(&flags::ACROSS, true, &flags::LONG));
                 return Err(OptionsError::Useless(&flags::ACROSS, true, &flags::LONG));
-            }
-            else if matches.has(&flags::ONE_LINE)? {
+            } else if matches.has(&flags::ONE_LINE)? {
                 return Err(OptionsError::Useless(&flags::ONE_LINE, true, &flags::LONG));
                 return Err(OptionsError::Useless(&flags::ONE_LINE, true, &flags::LONG));
             }
             }
         }
         }
@@ -146,7 +169,6 @@ impl details::Options {
     }
     }
 }
 }
 
 
-
 impl TerminalWidth {
 impl TerminalWidth {
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
         use crate::options::vars;
         use crate::options::vars;
@@ -166,84 +188,99 @@ impl TerminalWidth {
                     Err(OptionsError::FailedParse(arg_str.to_string(), source, e))
                     Err(OptionsError::FailedParse(arg_str.to_string(), source, e))
                 }
                 }
             }
             }
-        }
-        else if let Some(columns) = vars.get(vars::COLUMNS).and_then(|s| s.into_string().ok()) {
+        } else if let Some(columns) = vars.get(vars::COLUMNS).and_then(|s| s.into_string().ok()) {
             match columns.parse() {
             match columns.parse() {
-                Ok(width) => {
-                    Ok(Self::Set(width))
-                }
+                Ok(width) => Ok(Self::Set(width)),
                 Err(e) => {
                 Err(e) => {
                     let source = NumberSource::Env(vars::COLUMNS);
                     let source = NumberSource::Env(vars::COLUMNS);
                     Err(OptionsError::FailedParse(columns, source, e))
                     Err(OptionsError::FailedParse(columns, source, e))
                 }
                 }
             }
             }
-        }
-        else {
+        } else {
             Ok(Self::Automatic)
             Ok(Self::Automatic)
         }
         }
     }
     }
 }
 }
 
 
-
 impl RowThreshold {
 impl RowThreshold {
     fn deduce<V: Vars>(vars: &V) -> Result<Self, OptionsError> {
     fn deduce<V: Vars>(vars: &V) -> Result<Self, OptionsError> {
         use crate::options::vars;
         use crate::options::vars;
 
 
-        if let Some(columns) = vars.get_with_fallback(vars::EZA_GRID_ROWS, vars::EXA_GRID_ROWS).and_then(|s| s.into_string().ok()) {
+        if let Some(columns) = vars
+            .get_with_fallback(vars::EZA_GRID_ROWS, vars::EXA_GRID_ROWS)
+            .and_then(|s| s.into_string().ok())
+        {
             match columns.parse() {
             match columns.parse() {
-                Ok(rows) => {
-                    Ok(Self::MinimumRows(rows))
-                }
+                Ok(rows) => Ok(Self::MinimumRows(rows)),
                 Err(e) => {
                 Err(e) => {
-                    let source = NumberSource::Env(vars.source(vars::EZA_GRID_ROWS, vars::EXA_GRID_ROWS).unwrap());
+                    let source = NumberSource::Env(
+                        vars.source(vars::EZA_GRID_ROWS, vars::EXA_GRID_ROWS)
+                            .unwrap(),
+                    );
                     Err(OptionsError::FailedParse(columns, source, e))
                     Err(OptionsError::FailedParse(columns, source, e))
                 }
                 }
             }
             }
-        }
-        else {
+        } else {
             Ok(Self::AlwaysGrid)
             Ok(Self::AlwaysGrid)
         }
         }
     }
     }
 }
 }
 
 
-
 impl TableOptions {
 impl TableOptions {
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
         let time_format = TimeFormat::deduce(matches, vars)?;
         let time_format = TimeFormat::deduce(matches, vars)?;
         let size_format = SizeFormat::deduce(matches)?;
         let size_format = SizeFormat::deduce(matches)?;
         let user_format = UserFormat::deduce(matches)?;
         let user_format = UserFormat::deduce(matches)?;
         let columns = Columns::deduce(matches)?;
         let columns = Columns::deduce(matches)?;
-        Ok(Self { size_format, time_format, user_format, columns })
+        Ok(Self {
+            size_format,
+            time_format,
+            user_format,
+            columns,
+        })
     }
     }
 }
 }
 
 
-
 impl Columns {
 impl Columns {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
         let time_types = TimeTypes::deduce(matches)?;
         let time_types = TimeTypes::deduce(matches)?;
 
 
         let git = matches.has(&flags::GIT)? && !matches.has(&flags::NO_GIT)?;
         let git = matches.has(&flags::GIT)? && !matches.has(&flags::NO_GIT)?;
         let subdir_git_repos = matches.has(&flags::GIT_REPOS)? && !matches.has(&flags::NO_GIT)?;
         let subdir_git_repos = matches.has(&flags::GIT_REPOS)? && !matches.has(&flags::NO_GIT)?;
-        let subdir_git_repos_no_stat = !subdir_git_repos && matches.has(&flags::GIT_REPOS_NO_STAT)? && !matches.has(&flags::NO_GIT)?;
-
-        let blocksize        = matches.has(&flags::BLOCKSIZE)?;
-        let group            = matches.has(&flags::GROUP)?;
-        let inode            = matches.has(&flags::INODE)?;
-        let links            = matches.has(&flags::LINKS)?;
-        let octal            = matches.has(&flags::OCTAL)?;
+        let subdir_git_repos_no_stat = !subdir_git_repos
+            && matches.has(&flags::GIT_REPOS_NO_STAT)?
+            && !matches.has(&flags::NO_GIT)?;
+
+        let blocksize = matches.has(&flags::BLOCKSIZE)?;
+        let group = matches.has(&flags::GROUP)?;
+        let inode = matches.has(&flags::INODE)?;
+        let links = matches.has(&flags::LINKS)?;
+        let octal = matches.has(&flags::OCTAL)?;
         let security_context = xattr::ENABLED && matches.has(&flags::SECURITY_CONTEXT)?;
         let security_context = xattr::ENABLED && matches.has(&flags::SECURITY_CONTEXT)?;
 
 
-        let permissions = ! matches.has(&flags::NO_PERMISSIONS)?;
-        let filesize =    ! matches.has(&flags::NO_FILESIZE)?;
-        let user =        ! matches.has(&flags::NO_USER)?;
-
-        Ok(Self { time_types, inode, links, blocksize, group, git, subdir_git_repos, subdir_git_repos_no_stat, octal, security_context, permissions, filesize, user })
+        let permissions = !matches.has(&flags::NO_PERMISSIONS)?;
+        let filesize = !matches.has(&flags::NO_FILESIZE)?;
+        let user = !matches.has(&flags::NO_USER)?;
+
+        Ok(Self {
+            time_types,
+            inode,
+            links,
+            blocksize,
+            group,
+            git,
+            subdir_git_repos,
+            subdir_git_repos_no_stat,
+            octal,
+            security_context,
+            permissions,
+            filesize,
+            user,
+        })
     }
     }
 }
 }
 
 
-
 impl SizeFormat {
 impl SizeFormat {
-
     /// Determine which file size to use in the file size column based on
     /// Determine which file size to use in the file size column based on
     /// the user’s options.
     /// the user’s options.
     ///
     ///
@@ -256,42 +293,37 @@ impl SizeFormat {
         let flag = matches.has_where(|f| f.matches(&flags::BINARY) || f.matches(&flags::BYTES))?;
         let flag = matches.has_where(|f| f.matches(&flags::BINARY) || f.matches(&flags::BYTES))?;
 
 
         Ok(match flag {
         Ok(match flag {
-            Some(f) if f.matches(&flags::BINARY)  => Self::BinaryBytes,
-            Some(f) if f.matches(&flags::BYTES)   => Self::JustBytes,
-            _                                     => Self::DecimalBytes,
+            Some(f) if f.matches(&flags::BINARY) => Self::BinaryBytes,
+            Some(f) if f.matches(&flags::BYTES) => Self::JustBytes,
+            _ => Self::DecimalBytes,
         })
         })
     }
     }
 }
 }
 
 
-
 impl TimeFormat {
 impl TimeFormat {
-
     /// Determine how time should be formatted in timestamp columns.
     /// Determine how time should be formatted in timestamp columns.
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
-        let word =
-            if let Some(w) = matches.get(&flags::TIME_STYLE)? {
-                w.to_os_string()
+        let word = if let Some(w) = matches.get(&flags::TIME_STYLE)? {
+            w.to_os_string()
+        } else {
+            use crate::options::vars;
+            match vars.get(vars::TIME_STYLE) {
+                Some(ref t) if !t.is_empty() => t.clone(),
+                _ => return Ok(Self::DefaultFormat),
             }
             }
-            else {
-                use crate::options::vars;
-                match vars.get(vars::TIME_STYLE) {
-                    Some(ref t) if ! t.is_empty()  => t.clone(),
-                    _                              => return Ok(Self::DefaultFormat)
-                }
-            };
+        };
 
 
         match word.to_string_lossy().as_ref() {
         match word.to_string_lossy().as_ref() {
-            "default"  => Ok(Self::DefaultFormat),
+            "default" => Ok(Self::DefaultFormat),
             "relative" => Ok(Self::Relative),
             "relative" => Ok(Self::Relative),
-            "iso"      => Ok(Self::ISOFormat),
+            "iso" => Ok(Self::ISOFormat),
             "long-iso" => Ok(Self::LongISO),
             "long-iso" => Ok(Self::LongISO),
             "full-iso" => Ok(Self::FullISO),
             "full-iso" => Ok(Self::FullISO),
-            _ => Err(OptionsError::BadArgument(&flags::TIME_STYLE, word))
+            _ => Err(OptionsError::BadArgument(&flags::TIME_STYLE, word)),
         }
         }
     }
     }
 }
 }
 
 
-
 impl UserFormat {
 impl UserFormat {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
         let flag = matches.has(&flags::NUMERIC)?;
         let flag = matches.has(&flags::NUMERIC)?;
@@ -299,9 +331,7 @@ impl UserFormat {
     }
     }
 }
 }
 
 
-
 impl TimeTypes {
 impl TimeTypes {
-
     /// Determine which of a file’s time fields should be displayed for it
     /// Determine which of a file’s time fields should be displayed for it
     /// based on the user’s options.
     /// based on the user’s options.
     ///
     ///
@@ -315,47 +345,48 @@ impl TimeTypes {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
     fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
         let possible_word = matches.get(&flags::TIME)?;
         let possible_word = matches.get(&flags::TIME)?;
         let modified = matches.has(&flags::MODIFIED)?;
         let modified = matches.has(&flags::MODIFIED)?;
-        let changed  = matches.has(&flags::CHANGED)?;
+        let changed = matches.has(&flags::CHANGED)?;
         let accessed = matches.has(&flags::ACCESSED)?;
         let accessed = matches.has(&flags::ACCESSED)?;
-        let created  = matches.has(&flags::CREATED)?;
+        let created = matches.has(&flags::CREATED)?;
 
 
         let no_time = matches.has(&flags::NO_TIME)?;
         let no_time = matches.has(&flags::NO_TIME)?;
 
 
+        #[rustfmt::skip]
         let time_types = if no_time {
         let time_types = if no_time {
-            Self { modified: false, changed: false, accessed: false, created: false }
+            Self {
+                modified: false,
+                changed: false,
+                accessed: false,
+                created: false,
+            }
         } else if let Some(word) = possible_word {
         } else if let Some(word) = possible_word {
             if modified {
             if modified {
                 return Err(OptionsError::Useless(&flags::MODIFIED, true, &flags::TIME));
                 return Err(OptionsError::Useless(&flags::MODIFIED, true, &flags::TIME));
-            }
-            else if changed {
+            } else if changed {
                 return Err(OptionsError::Useless(&flags::CHANGED, true, &flags::TIME));
                 return Err(OptionsError::Useless(&flags::CHANGED, true, &flags::TIME));
-            }
-            else if accessed {
+            } else if accessed {
                 return Err(OptionsError::Useless(&flags::ACCESSED, true, &flags::TIME));
                 return Err(OptionsError::Useless(&flags::ACCESSED, true, &flags::TIME));
-            }
-            else if created {
+            } else if created {
                 return Err(OptionsError::Useless(&flags::CREATED, true, &flags::TIME));
                 return Err(OptionsError::Useless(&flags::CREATED, true, &flags::TIME));
-            }
-            else if word == "mod" || word == "modified" {
+            } else if word == "mod" || word == "modified" {
                 Self { modified: true,  changed: false, accessed: false, created: false }
                 Self { modified: true,  changed: false, accessed: false, created: false }
-            }
-            else if word == "ch" || word == "changed" {
+            } else if word == "ch" || word == "changed" {
                 Self { modified: false, changed: true,  accessed: false, created: false }
                 Self { modified: false, changed: true,  accessed: false, created: false }
-            }
-            else if word == "acc" || word == "accessed" {
+            } else if word == "acc" || word == "accessed" {
                 Self { modified: false, changed: false, accessed: true,  created: false }
                 Self { modified: false, changed: false, accessed: true,  created: false }
-            }
-            else if word == "cr" || word == "created" {
+            } else if word == "cr" || word == "created" {
                 Self { modified: false, changed: false, accessed: false, created: true  }
                 Self { modified: false, changed: false, accessed: false, created: true  }
-            }
-            else {
+            } else {
                 return Err(OptionsError::BadArgument(&flags::TIME, word.into()));
                 return Err(OptionsError::BadArgument(&flags::TIME, word.into()));
             }
             }
-        }
-        else if modified || changed || accessed || created {
-            Self { modified, changed, accessed, created }
-        }
-        else {
+        } else if modified || changed || accessed || created {
+            Self {
+                modified,
+                changed,
+                accessed,
+                created,
+            }
+        } else {
             Self::default()
             Self::default()
         };
         };
 
 
@@ -363,33 +394,49 @@ impl TimeTypes {
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod test {
 mod test {
     use super::*;
     use super::*;
-    use std::ffi::OsString;
     use crate::options::flags;
     use crate::options::flags;
-    use crate::options::parser::{Flag, Arg};
+    use crate::options::parser::{Arg, Flag};
+    use std::ffi::OsString;
 
 
     use crate::options::test::parse_for_test;
     use crate::options::test::parse_for_test;
     use crate::options::test::Strictnesses::*;
     use crate::options::test::Strictnesses::*;
 
 
-    static TEST_ARGS: &[&Arg] = &[ &flags::BINARY, &flags::BYTES,    &flags::TIME_STYLE,
-                                   &flags::TIME,   &flags::MODIFIED, &flags::CHANGED,
-                                   &flags::CREATED, &flags::ACCESSED,
-                                   &flags::HEADER, &flags::GROUP,  &flags::INODE, &flags::GIT,
-                                   &flags::LINKS,  &flags::BLOCKSIZE, &flags::LONG,  &flags::LEVEL,
-                                   &flags::GRID,   &flags::ACROSS, &flags::ONE_LINE, &flags::TREE,
-                                   &flags::NUMERIC ];
+    static TEST_ARGS: &[&Arg] = &[
+        &flags::BINARY,
+        &flags::BYTES,
+        &flags::TIME_STYLE,
+        &flags::TIME,
+        &flags::MODIFIED,
+        &flags::CHANGED,
+        &flags::CREATED,
+        &flags::ACCESSED,
+        &flags::HEADER,
+        &flags::GROUP,
+        &flags::INODE,
+        &flags::GIT,
+        &flags::LINKS,
+        &flags::BLOCKSIZE,
+        &flags::LONG,
+        &flags::LEVEL,
+        &flags::GRID,
+        &flags::ACROSS,
+        &flags::ONE_LINE,
+        &flags::TREE,
+        &flags::NUMERIC,
+    ];
 
 
     macro_rules! test {
     macro_rules! test {
-
         ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
         ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
             /// Macro that writes a test.
             /// Macro that writes a test.
             /// If testing both strictnesses, they’ll both be done in the same function.
             /// If testing both strictnesses, they’ll both be done in the same function.
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf)
+                }) {
                     assert_eq!(result, $result);
                     assert_eq!(result, $result);
                 }
                 }
             }
             }
@@ -400,7 +447,9 @@ mod test {
             /// This is needed because sometimes the Ok type doesn’t implement `PartialEq`.
             /// This is needed because sometimes the Ok type doesn’t implement `PartialEq`.
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf)
+                }) {
                     assert_eq!(result.unwrap_err(), $result);
                     assert_eq!(result.unwrap_err(), $result);
                 }
                 }
             }
             }
@@ -411,22 +460,25 @@ mod test {
             /// Instead of using `PartialEq`, this just tests if it matches a pat.
             /// Instead of using `PartialEq`, this just tests if it matches a pat.
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf)
+                }) {
                     println!("Testing {:?}", result);
                     println!("Testing {:?}", result);
                     match result {
                     match result {
                         $pat => assert!(true),
                         $pat => assert!(true),
-                        _    => assert!(false),
+                        _ => assert!(false),
                     }
                     }
                 }
                 }
             }
             }
         };
         };
 
 
-
         ($name:ident: $type:ident <- $inputs:expr, $vars:expr; $stricts:expr => err $result:expr) => {
         ($name:ident: $type:ident <- $inputs:expr, $vars:expr; $stricts:expr => err $result:expr) => {
             /// Like above, but with $vars.
             /// Like above, but with $vars.
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &$vars)) {
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf, &$vars)
+                }) {
                     assert_eq!(result.unwrap_err(), $result);
                     assert_eq!(result.unwrap_err(), $result);
                 }
                 }
             }
             }
@@ -436,18 +488,19 @@ mod test {
             /// Like further above, but with $vars.
             /// Like further above, but with $vars.
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &$vars)) {
+                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
+                    $type::deduce(mf, &$vars)
+                }) {
                     println!("Testing {:?}", result);
                     println!("Testing {:?}", result);
                     match result {
                     match result {
                         $pat => assert!(true),
                         $pat => assert!(true),
-                        _    => assert!(false),
+                        _ => assert!(false),
                     }
                     }
                 }
                 }
             }
             }
         };
         };
     }
     }
 
 
-
     mod size_formats {
     mod size_formats {
         use super::*;
         use super::*;
 
 
@@ -470,7 +523,6 @@ mod test {
         test!(both_8:  SizeFormat <- ["--bytes",  "--bytes"];   Complain => err OptionsError::Duplicate(Flag::Long("bytes"),  Flag::Long("bytes")));
         test!(both_8:  SizeFormat <- ["--bytes",  "--bytes"];   Complain => err OptionsError::Duplicate(Flag::Long("bytes"),  Flag::Long("bytes")));
     }
     }
 
 
-
     mod time_formats {
     mod time_formats {
         use super::*;
         use super::*;
 
 
@@ -505,7 +557,6 @@ mod test {
         test!(override_env:     TimeFormat <- ["--time-style=full-iso"], Some("long-iso".into());  Both => like Ok(TimeFormat::FullISO));
         test!(override_env:     TimeFormat <- ["--time-style=full-iso"], Some("long-iso".into());  Both => like Ok(TimeFormat::FullISO));
     }
     }
 
 
-
     mod time_types {
     mod time_types {
         use super::*;
         use super::*;
 
 
@@ -541,7 +592,6 @@ mod test {
         // Multiples
         // Multiples
         test!(time_uu:   TimeTypes <- ["-u", "--modified"];    Both => Ok(TimeTypes { modified: true,  changed: false, accessed: true,  created: false }));
         test!(time_uu:   TimeTypes <- ["-u", "--modified"];    Both => Ok(TimeTypes { modified: true,  changed: false, accessed: true,  created: false }));
 
 
-
         // Errors
         // Errors
         test!(time_tea:  TimeTypes <- ["--time=tea"];          Both => err OptionsError::BadArgument(&flags::TIME, OsString::from("tea")));
         test!(time_tea:  TimeTypes <- ["--time=tea"];          Both => err OptionsError::BadArgument(&flags::TIME, OsString::from("tea")));
         test!(t_ea:      TimeTypes <- ["-tea"];                Both => err OptionsError::BadArgument(&flags::TIME, OsString::from("ea")));
         test!(t_ea:      TimeTypes <- ["-tea"];                Both => err OptionsError::BadArgument(&flags::TIME, OsString::from("ea")));
@@ -551,13 +601,11 @@ mod test {
         test!(overridden_2: TimeTypes <- ["-tcr", "-tmod"];    Complain => err OptionsError::Duplicate(Flag::Short(b't'), Flag::Short(b't')));
         test!(overridden_2: TimeTypes <- ["-tcr", "-tmod"];    Complain => err OptionsError::Duplicate(Flag::Short(b't'), Flag::Short(b't')));
     }
     }
 
 
-
     mod views {
     mod views {
         use super::*;
         use super::*;
 
 
         use crate::output::grid::Options as GridOptions;
         use crate::output::grid::Options as GridOptions;
 
 
-
         // Default
         // Default
         test!(empty:         Mode <- [], None;            Both => like Ok(Mode::Grid(_)));
         test!(empty:         Mode <- [], None;            Both => like Ok(Mode::Grid(_)));
 
 

+ 9 - 15
src/output/cell.rs

@@ -3,10 +3,9 @@
 use std::iter::Sum;
 use std::iter::Sum;
 use std::ops::{Add, Deref, DerefMut};
 use std::ops::{Add, Deref, DerefMut};
 
 
-use ansiterm::{Style, ANSIString, ANSIStrings};
+use ansiterm::{ANSIString, ANSIStrings, Style};
 use unicode_width::UnicodeWidthStr;
 use unicode_width::UnicodeWidthStr;
 
 
-
 /// 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.
 ///
 ///
@@ -19,7 +18,6 @@ use unicode_width::UnicodeWidthStr;
 /// type by that name too.)
 /// type by that name too.)
 #[derive(PartialEq, Debug, Clone, Default)]
 #[derive(PartialEq, Debug, Clone, Default)]
 pub struct TextCell {
 pub struct TextCell {
-
     /// The contents of this cell, as a vector of ANSI-styled strings.
     /// The contents of this cell, as a vector of ANSI-styled strings.
     pub contents: TextCellContents,
     pub contents: TextCellContents,
 
 
@@ -36,14 +34,13 @@ impl Deref for TextCell {
 }
 }
 
 
 impl TextCell {
 impl TextCell {
-
     /// Creates a new text cell that holds the given text in the given style,
     /// Creates a new text cell that holds the given text in the given style,
     /// computing the Unicode width of the text.
     /// computing the Unicode width of the text.
     pub fn paint(style: Style, text: String) -> Self {
     pub fn paint(style: Style, text: String) -> Self {
         let width = DisplayWidth::from(&*text);
         let width = DisplayWidth::from(&*text);
 
 
         Self {
         Self {
-            contents: vec![ style.paint(text) ].into(),
+            contents: vec![style.paint(text)].into(),
             width,
             width,
         }
         }
     }
     }
@@ -55,7 +52,7 @@ impl TextCell {
         let width = DisplayWidth::from(text);
         let width = DisplayWidth::from(text);
 
 
         Self {
         Self {
-            contents: vec![ style.paint(text) ].into(),
+            contents: vec![style.paint(text)].into(),
             width,
             width,
         }
         }
     }
     }
@@ -68,8 +65,8 @@ impl TextCell {
     /// tabular data when there is *something* in each cell.
     /// tabular data when there is *something* in each cell.
     pub fn blank(style: Style) -> Self {
     pub fn blank(style: Style) -> Self {
         Self {
         Self {
-            contents: vec![ style.paint("-") ].into(),
-            width:    DisplayWidth::from(1),
+            contents: vec![style.paint("-")].into(),
+            width: DisplayWidth::from(1),
         }
         }
     }
     }
 
 
@@ -96,7 +93,6 @@ impl TextCell {
     }
     }
 }
 }
 
 
-
 // I’d like to eventually abstract cells so that instead of *every* cell
 // I’d like to eventually abstract cells so that instead of *every* cell
 // storing a vector, only variable-length cells would, and individual cells
 // storing a vector, only variable-length cells would, and individual cells
 // would just store an array of a fixed length (which would usually be just 1
 // would just store an array of a fixed length (which would usually be just 1
@@ -123,7 +119,6 @@ impl TextCell {
 //
 //
 // But exa still has bugs and I need to fix those first :(
 // But exa still has bugs and I need to fix those first :(
 
 
-
 /// The contents of a text cell, as a vector of ANSI-styled strings.
 /// The contents of a text cell, as a vector of ANSI-styled strings.
 ///
 ///
 /// It’s possible to use this type directly in the case where you want a
 /// It’s possible to use this type directly in the case where you want a
@@ -152,7 +147,6 @@ impl Deref for TextCellContents {
 // above can just access the value directly.
 // above can just access the value directly.
 
 
 impl TextCellContents {
 impl TextCellContents {
-
     /// Produces an `ANSIStrings` value that can be used to print the styled
     /// Produces an `ANSIStrings` value that can be used to print the styled
     /// values of this cell as an ANSI-terminal-formatted string.
     /// values of this cell as an ANSI-terminal-formatted string.
     pub fn strings(&self) -> ANSIStrings<'_> {
     pub fn strings(&self) -> ANSIStrings<'_> {
@@ -162,7 +156,8 @@ impl TextCellContents {
     /// Calculates the width that a cell with these contents would take up, by
     /// Calculates the width that a cell with these contents would take up, by
     /// counting the number of characters in each unformatted ANSI string.
     /// counting the number of characters in each unformatted ANSI string.
     pub fn width(&self) -> DisplayWidth {
     pub fn width(&self) -> DisplayWidth {
-        self.0.iter()
+        self.0
+            .iter()
             .map(|anstr| DisplayWidth::from(&**anstr))
             .map(|anstr| DisplayWidth::from(&**anstr))
             .sum()
             .sum()
     }
     }
@@ -177,7 +172,6 @@ impl TextCellContents {
     }
     }
 }
 }
 
 
-
 /// The Unicode “display width” of a string.
 /// The Unicode “display width” of a string.
 ///
 ///
 /// This is related to the number of *graphemes* of a string, rather than the
 /// This is related to the number of *graphemes* of a string, rather than the
@@ -238,13 +232,13 @@ impl Add<usize> for DisplayWidth {
 
 
 impl Sum for DisplayWidth {
 impl Sum for DisplayWidth {
     fn sum<I>(iter: I) -> Self
     fn sum<I>(iter: I) -> Self
-    where I: Iterator<Item = Self>
+    where
+        I: Iterator<Item = Self>,
     {
     {
         iter.fold(Self(0), Add::add)
         iter.fold(Self(0), Add::add)
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod width_unit_test {
 mod width_unit_test {
     use super::DisplayWidth;
     use super::DisplayWidth;

+ 116 - 62
src/output/details.rs

@@ -59,7 +59,6 @@
 //! means that we must wait until every row has been added to the table before it
 //! means that we must wait until every row has been added to the table before it
 //! can be displayed, in order to make sure that every column is wide enough.
 //! can be displayed, in order to make sure that every column is wide enough.
 
 
-
 use std::io::{self, Write};
 use std::io::{self, Write};
 use std::mem::MaybeUninit;
 use std::mem::MaybeUninit;
 use std::path::PathBuf;
 use std::path::PathBuf;
@@ -70,19 +69,18 @@ use scoped_threadpool::Pool;
 
 
 use log::*;
 use log::*;
 
 
-use crate::fs::{Dir, File};
 use crate::fs::dir_action::RecurseOptions;
 use crate::fs::dir_action::RecurseOptions;
 use crate::fs::feature::git::GitCache;
 use crate::fs::feature::git::GitCache;
 use crate::fs::feature::xattr::Attribute;
 use crate::fs::feature::xattr::Attribute;
 use crate::fs::fields::SecurityContextType;
 use crate::fs::fields::SecurityContextType;
 use crate::fs::filter::FileFilter;
 use crate::fs::filter::FileFilter;
+use crate::fs::{Dir, File};
 use crate::output::cell::TextCell;
 use crate::output::cell::TextCell;
 use crate::output::file_name::Options as FileStyle;
 use crate::output::file_name::Options as FileStyle;
-use crate::output::table::{Table, Options as TableOptions, Row as TableRow};
-use crate::output::tree::{TreeTrunk, TreeParams, TreeDepth};
+use crate::output::table::{Options as TableOptions, Row as TableRow, Table};
+use crate::output::tree::{TreeDepth, TreeParams, TreeTrunk};
 use crate::theme::Theme;
 use crate::theme::Theme;
 
 
-
 /// With the **Details** view, the output gets formatted into columns, with
 /// With the **Details** view, the output gets formatted into columns, with
 /// each `Column` object showing some piece of information about the file,
 /// each `Column` object showing some piece of information about the file,
 /// such as its size, or its permissions.
 /// such as its size, or its permissions.
@@ -94,10 +92,10 @@ use crate::theme::Theme;
 ///
 ///
 /// Almost all the heavy lifting is done in a Table object, which handles the
 /// Almost all the heavy lifting is done in a Table object, which handles the
 /// columns for each row.
 /// columns for each row.
-#[allow(clippy::struct_excessive_bools)] /// This clearly isn't a state machine
+#[allow(clippy::struct_excessive_bools)]
+/// This clearly isn't a state machine
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub struct Options {
 pub struct Options {
-
     /// Options specific to drawing a table.
     /// Options specific to drawing a table.
     ///
     ///
     /// Directories themselves can pick which columns are *added* to this
     /// Directories themselves can pick which columns are *added* to this
@@ -117,7 +115,6 @@ pub struct Options {
     pub mounts: bool,
     pub mounts: bool,
 }
 }
 
 
-
 pub struct Render<'a> {
 pub struct Render<'a> {
     pub dir: Option<&'a Dir>,
     pub dir: Option<&'a Dir>,
     pub files: Vec<File<'a>>,
     pub files: Vec<File<'a>>,
@@ -139,7 +136,7 @@ pub struct Render<'a> {
     pub git: Option<&'a GitCache>,
     pub git: Option<&'a GitCache>,
 }
 }
 
 
-
+#[rustfmt::skip]
 struct Egg<'a> {
 struct Egg<'a> {
     table_row: Option<TableRow>,
     table_row: Option<TableRow>,
     xattrs:    &'a [Attribute],
     xattrs:    &'a [Attribute],
@@ -154,7 +151,6 @@ impl<'a> AsRef<File<'a>> for Egg<'a> {
     }
     }
 }
 }
 
 
-
 impl<'a> Render<'a> {
 impl<'a> Render<'a> {
     pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
     pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
         let n_cpus = match num_cpus::get() as u32 {
         let n_cpus = match num_cpus::get() as u32 {
@@ -166,9 +162,17 @@ impl<'a> Render<'a> {
 
 
         if let Some(ref table) = self.opts.table {
         if let Some(ref table) = self.opts.table {
             match (self.git, self.dir) {
             match (self.git, self.dir) {
-                (Some(g), Some(d))  => if ! g.has_anything_for(&d.path) { self.git = None },
-                (Some(g), None)     => if ! self.files.iter().any(|f| g.has_anything_for(&f.path)) { self.git = None },
-                (None,    _)        => {/* Keep Git how it is */},
+                (Some(g), Some(d)) => {
+                    if !g.has_anything_for(&d.path) {
+                        self.git = None;
+                    }
+                }
+                (Some(g), None) => {
+                    if !self.files.iter().any(|f| g.has_anything_for(&f.path)) {
+                        self.git = None;
+                    }
+                }
+                (None, _) => { /* Keep Git how it is */ }
             }
             }
 
 
             let mut table = Table::new(table, self.git, self.theme);
             let mut table = Table::new(table, self.git, self.theme);
@@ -182,14 +186,25 @@ impl<'a> Render<'a> {
             // This is weird, but I can’t find a way around it:
             // This is weird, but I can’t find a way around it:
             // https://internals.rust-lang.org/t/should-option-mut-t-implement-copy/3715/6
             // https://internals.rust-lang.org/t/should-option-mut-t-implement-copy/3715/6
             let mut table = Some(table);
             let mut table = Some(table);
-            self.add_files_to_table(&mut pool, &mut table, &mut rows, &self.files, TreeDepth::root());
+            self.add_files_to_table(
+                &mut pool,
+                &mut table,
+                &mut rows,
+                &self.files,
+                TreeDepth::root(),
+            );
 
 
             for row in self.iterate_with_table(table.unwrap(), rows) {
             for row in self.iterate_with_table(table.unwrap(), rows) {
                 writeln!(w, "{}", row.strings())?;
                 writeln!(w, "{}", row.strings())?;
             }
             }
-        }
-        else {
-            self.add_files_to_table(&mut pool, &mut None, &mut rows, &self.files, TreeDepth::root());
+        } else {
+            self.add_files_to_table(
+                &mut pool,
+                &mut None,
+                &mut rows,
+                &self.files,
+                TreeDepth::root(),
+            );
 
 
             for row in self.iterate(rows) {
             for row in self.iterate(rows) {
                 writeln!(w, "{}", row.strings())?;
                 writeln!(w, "{}", row.strings())?;
@@ -204,20 +219,30 @@ impl<'a> Render<'a> {
         // Do not show the hint '@' if the only extended attribute is the security
         // Do not show the hint '@' if the only extended attribute is the security
         // attribute and the security attribute column is active.
         // attribute and the security attribute column is active.
         let xattr_count = file.extended_attributes().len();
         let xattr_count = file.extended_attributes().len();
-        let selinux_ctx_shown = self.opts.secattr && match file.security_context().context {
-            SecurityContextType::SELinux(_) => true,
-            SecurityContextType::None       => false,
-        };
+        let selinux_ctx_shown = self.opts.secattr
+            && match file.security_context().context {
+                SecurityContextType::SELinux(_) => true,
+                SecurityContextType::None => false,
+            };
         xattr_count > 1 || (xattr_count == 1 && !selinux_ctx_shown)
         xattr_count > 1 || (xattr_count == 1 && !selinux_ctx_shown)
     }
     }
 
 
     /// Adds files to the table, possibly recursively. This is easily
     /// Adds files to the table, possibly recursively. This is easily
     /// parallelisable, and uses a pool of threads.
     /// parallelisable, and uses a pool of threads.
-    fn add_files_to_table<'dir>(&self, pool: &mut Pool, table: &mut Option<Table<'a>>, rows: &mut Vec<Row>, src: &[File<'dir>], depth: TreeDepth) {
-        use std::sync::{Arc, Mutex};
+    fn add_files_to_table<'dir>(
+        &self,
+        pool: &mut Pool,
+        table: &mut Option<Table<'a>>,
+        rows: &mut Vec<Row>,
+        src: &[File<'dir>],
+        depth: TreeDepth,
+    ) {
         use crate::fs::feature::xattr;
         use crate::fs::feature::xattr;
+        use std::sync::{Arc, Mutex};
 
 
-        let mut file_eggs = (0..src.len()).map(|_| MaybeUninit::uninit()).collect::<Vec<_>>();
+        let mut file_eggs = (0..src.len())
+            .map(|_| MaybeUninit::uninit())
+            .collect::<Vec<_>>();
 
 
         pool.scoped(|scoped| {
         pool.scoped(|scoped| {
             let file_eggs = Arc::new(Mutex::new(&mut file_eggs));
             let file_eggs = Arc::new(Mutex::new(&mut file_eggs));
@@ -257,12 +282,13 @@ impl<'a> Render<'a> {
                         &[]
                         &[]
                     };
                     };
 
 
-                    let table_row = table.as_ref()
-                                         .map(|t| t.row_for_file(file, self.show_xattr_hint(file)));
+                    let table_row = table
+                        .as_ref()
+                        .map(|t| t.row_for_file(file, self.show_xattr_hint(file)));
 
 
                     let mut dir = None;
                     let mut dir = None;
                     if let Some(r) = self.recurse {
                     if let Some(r) = self.recurse {
-                        if file.is_directory() && r.tree && ! r.is_too_deep(depth.0) {
+                        if file.is_directory() && r.tree && !r.is_too_deep(depth.0) {
                             trace!("matching on to_dir");
                             trace!("matching on to_dir");
                             match file.to_dir() {
                             match file.to_dir() {
                                 Ok(d) => {
                                 Ok(d) => {
@@ -275,7 +301,13 @@ impl<'a> Render<'a> {
                         }
                         }
                     };
                     };
 
 
-                    let egg = Egg { table_row, xattrs, errors, dir, file };
+                    let egg = Egg {
+                        table_row,
+                        xattrs,
+                        errors,
+                        dir,
+                        file,
+                    };
                     unsafe { std::ptr::write(file_eggs.lock().unwrap()[idx].as_mut_ptr(), egg) }
                     unsafe { std::ptr::write(file_eggs.lock().unwrap()[idx].as_mut_ptr(), egg) }
                 });
                 });
             }
             }
@@ -293,22 +325,29 @@ impl<'a> Render<'a> {
                 t.add_widths(row);
                 t.add_widths(row);
             }
             }
 
 
-            let file_name = self.file_style.for_file(egg.file, self.theme)
-                                .with_link_paths()
-                                .with_mount_details(self.opts.mounts)
-                                .paint()
-                                .promote();
+            let file_name = self
+                .file_style
+                .for_file(egg.file, self.theme)
+                .with_link_paths()
+                .with_mount_details(self.opts.mounts)
+                .paint()
+                .promote();
 
 
             let row = Row {
             let row = Row {
-                tree:   tree_params,
-                cells:  egg.table_row,
-                name:   file_name,
+                tree: tree_params,
+                cells: egg.table_row,
+                name: file_name,
             };
             };
 
 
             rows.push(row);
             rows.push(row);
 
 
             if let Some(ref dir) = egg.dir {
             if let Some(ref dir) = egg.dir {
-                for file_to_add in dir.files(self.filter.dot_filter, self.git, self.git_ignoring, egg.file.deref_links) {
+                for file_to_add in dir.files(
+                    self.filter.dot_filter,
+                    self.git,
+                    self.git_ignoring,
+                    egg.file.deref_links,
+                ) {
                     match file_to_add {
                     match file_to_add {
                         Ok(f) => {
                         Ok(f) => {
                             files.push(f);
                             files.push(f);
@@ -321,13 +360,17 @@ impl<'a> Render<'a> {
 
 
                 self.filter.filter_child_files(&mut files);
                 self.filter.filter_child_files(&mut files);
 
 
-                if ! files.is_empty() {
+                if !files.is_empty() {
                     for xattr in egg.xattrs {
                     for xattr in egg.xattrs {
                         rows.push(self.render_xattr(xattr, TreeParams::new(depth.deeper(), false)));
                         rows.push(self.render_xattr(xattr, TreeParams::new(depth.deeper(), false)));
                     }
                     }
 
 
                     for (error, path) in errors {
                     for (error, path) in errors {
-                        rows.push(self.render_error(&error, TreeParams::new(depth.deeper(), false), path));
+                        rows.push(self.render_error(
+                            &error,
+                            TreeParams::new(depth.deeper(), false),
+                            path,
+                        ));
                     }
                     }
 
 
                     self.add_files_to_table(pool, table, rows, &files, depth.deeper());
                     self.add_files_to_table(pool, table, rows, &files, depth.deeper());
@@ -337,7 +380,8 @@ impl<'a> Render<'a> {
 
 
             let count = egg.xattrs.len();
             let count = egg.xattrs.len();
             for (index, xattr) in egg.xattrs.iter().enumerate() {
             for (index, xattr) in egg.xattrs.iter().enumerate() {
-                let params = TreeParams::new(depth.deeper(), errors.is_empty() && index == count - 1);
+                let params =
+                    TreeParams::new(depth.deeper(), errors.is_empty() && index == count - 1);
                 let r = self.render_xattr(xattr, params);
                 let r = self.render_xattr(xattr, params);
                 rows.push(r);
                 rows.push(r);
             }
             }
@@ -353,9 +397,9 @@ impl<'a> Render<'a> {
 
 
     pub fn render_header(&self, header: TableRow) -> Row {
     pub fn render_header(&self, header: TableRow) -> Row {
         Row {
         Row {
-            tree:     TreeParams::new(TreeDepth::root(), false),
-            cells:    Some(header),
-            name:     TextCell::paint_str(self.theme.ui.header, "Name"),
+            tree: TreeParams::new(TreeDepth::root(), false),
+            cells: Some(header),
+            name: TextCell::paint_str(self.theme.ui.header, "Name"),
         }
         }
     }
     }
 
 
@@ -371,16 +415,31 @@ impl<'a> Render<'a> {
         // TODO: broken_symlink() doesn’t quite seem like the right name for
         // TODO: broken_symlink() doesn’t quite seem like the right name for
         // the style that’s being used here. Maybe split it in two?
         // the style that’s being used here. Maybe split it in two?
         let name = TextCell::paint(self.theme.broken_symlink(), error_message);
         let name = TextCell::paint(self.theme.broken_symlink(), error_message);
-        Row { cells: None, name, tree }
+        Row {
+            cells: None,
+            name,
+            tree,
+        }
     }
     }
 
 
     fn render_xattr(&self, xattr: &Attribute, tree: TreeParams) -> Row {
     fn render_xattr(&self, xattr: &Attribute, tree: TreeParams) -> Row {
-        let name = TextCell::paint(self.theme.ui.perms.attribute, format!("{}=\"{}\"", xattr.name, xattr.value));
-        Row { cells: None, name, tree }
+        let name = TextCell::paint(
+            self.theme.ui.perms.attribute,
+            format!("{}=\"{}\"", xattr.name, xattr.value),
+        );
+        Row {
+            cells: None,
+            name,
+            tree,
+        }
     }
     }
 
 
     pub fn render_file(&self, cells: TableRow, name: TextCell, tree: TreeParams) -> Row {
     pub fn render_file(&self, cells: TableRow, name: TextCell, tree: TreeParams) -> Row {
-        Row { cells: Some(cells), name, tree }
+        Row {
+            cells: Some(cells),
+            name,
+            tree,
+        }
     }
     }
 
 
     pub fn iterate_with_table(&'a self, table: Table<'a>, rows: Vec<Row>) -> TableIter<'a> {
     pub fn iterate_with_table(&'a self, table: Table<'a>, rows: Vec<Row>) -> TableIter<'a> {
@@ -402,9 +461,7 @@ impl<'a> Render<'a> {
     }
     }
 }
 }
 
 
-
 pub struct Row {
 pub struct Row {
-
     /// Vector of cells to display.
     /// Vector of cells to display.
     ///
     ///
     /// Most of the rows will be used to display files’ metadata, so this will
     /// Most of the rows will be used to display files’ metadata, so this will
@@ -421,7 +478,7 @@ pub struct Row {
     pub tree: TreeParams,
     pub tree: TreeParams,
 }
 }
 
 
-
+#[rustfmt::skip]
 pub struct TableIter<'a> {
 pub struct TableIter<'a> {
     inner: VecIntoIter<Row>,
     inner: VecIntoIter<Row>,
     table: Table<'a>,
     table: Table<'a>,
@@ -436,15 +493,13 @@ impl<'a> Iterator for TableIter<'a> {
 
 
     fn next(&mut self) -> Option<Self::Item> {
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next().map(|row| {
         self.inner.next().map(|row| {
-            let mut cell =
-                if let Some(cells) = row.cells {
-                    self.table.render(cells)
-                }
-                else {
-                    let mut cell = TextCell::default();
-                    cell.add_spaces(self.total_width);
-                    cell
-                };
+            let mut cell = if let Some(cells) = row.cells {
+                self.table.render(cells)
+            } else {
+                let mut cell = TextCell::default();
+                cell.add_spaces(self.total_width);
+                cell
+            };
 
 
             for tree_part in self.tree_trunk.new_row(row.tree) {
             for tree_part in self.tree_trunk.new_row(row.tree) {
                 cell.push(self.tree_style.paint(tree_part.ascii_art()), 4);
                 cell.push(self.tree_style.paint(tree_part.ascii_art()), 4);
@@ -452,7 +507,7 @@ impl<'a> Iterator for TableIter<'a> {
 
 
             // If any tree characters have been printed, then add an extra
             // If any tree characters have been printed, then add an extra
             // space, which makes the output look much better.
             // space, which makes the output look much better.
-            if ! row.tree.is_at_root() {
+            if !row.tree.is_at_root() {
                 cell.add_spaces(1);
                 cell.add_spaces(1);
             }
             }
 
 
@@ -462,7 +517,6 @@ impl<'a> Iterator for TableIter<'a> {
     }
     }
 }
 }
 
 
-
 pub struct Iter {
 pub struct Iter {
     tree_trunk: TreeTrunk,
     tree_trunk: TreeTrunk,
     tree_style: Style,
     tree_style: Style,
@@ -482,7 +536,7 @@ impl Iterator for Iter {
 
 
             // If any tree characters have been printed, then add an extra
             // If any tree characters have been printed, then add an extra
             // space, which makes the output look much better.
             // space, which makes the output look much better.
-            if ! row.tree.is_at_root() {
+            if !row.tree.is_at_root() {
                 cell.add_spaces(1);
                 cell.add_spaces(1);
             }
             }
 
 

+ 0 - 1
src/output/escape.rs

@@ -1,6 +1,5 @@
 use ansiterm::{ANSIString, Style};
 use ansiterm::{ANSIString, Style};
 
 
-
 pub fn escape(string: String, bits: &mut Vec<ANSIString<'_>>, good: Style, bad: Style) {
 pub fn escape(string: String, bits: &mut Vec<ANSIString<'_>>, good: Style, bad: Style) {
     // if the string has no control character
     // if the string has no control character
     if string.chars().all(|c| !c.is_control()) {
     if string.chars().all(|c| !c.is_control()) {

+ 60 - 59
src/output/file_name.rs

@@ -13,29 +13,34 @@ use crate::output::render::FiletypeColours;
 /// Basically a file name factory.
 /// Basically a file name factory.
 #[derive(Debug, Copy, Clone)]
 #[derive(Debug, Copy, Clone)]
 pub struct Options {
 pub struct Options {
-
     /// Whether to append file class characters to file names.
     /// Whether to append file class characters to file names.
     pub classify: Classify,
     pub classify: Classify,
 
 
     /// Whether to prepend icon characters before file names.
     /// Whether to prepend icon characters before file names.
     pub show_icons: ShowIcons,
     pub show_icons: ShowIcons,
-    
+
     /// Whether to make file names hyperlinks.
     /// Whether to make file names hyperlinks.
     pub embed_hyperlinks: EmbedHyperlinks,
     pub embed_hyperlinks: EmbedHyperlinks,
 }
 }
 
 
 impl Options {
 impl Options {
-
     /// Create a new `FileName` that prints the given file’s name, painting it
     /// Create a new `FileName` that prints the given file’s name, painting it
     /// with the remaining arguments.
     /// with the remaining arguments.
-    pub fn for_file<'a, 'dir, C>(self, file: &'a File<'dir>, colours: &'a C) -> FileName<'a, 'dir, C> {
+    pub fn for_file<'a, 'dir, C>(
+        self,
+        file: &'a File<'dir>,
+        colours: &'a C,
+    ) -> FileName<'a, 'dir, C> {
         FileName {
         FileName {
             file,
             file,
             colours,
             colours,
             link_style: LinkStyle::JustFilenames,
             link_style: LinkStyle::JustFilenames,
-            options:    self,
-            target:     if file.is_link() { Some(file.link_target()) }
-                                     else { None },
+            options: self,
+            target: if file.is_link() {
+                Some(file.link_target())
+            } else {
+                None
+            },
             mount_style: MountStyle::JustDirectoryNames,
             mount_style: MountStyle::JustDirectoryNames,
             mounted_fs: file.mount_point_info(),
             mounted_fs: file.mount_point_info(),
         }
         }
@@ -46,7 +51,6 @@ impl Options {
 /// links, depending on how long the resulting Cell can be.
 /// links, depending on how long the resulting Cell can be.
 #[derive(PartialEq, Debug, Copy, Clone)]
 #[derive(PartialEq, Debug, Copy, Clone)]
 enum LinkStyle {
 enum LinkStyle {
-
     /// Just display the file names, but colour them differently if they’re
     /// Just display the file names, but colour them differently if they’re
     /// a broken link or can’t be followed.
     /// a broken link or can’t be followed.
     JustFilenames,
     JustFilenames,
@@ -57,11 +61,9 @@ enum LinkStyle {
     FullLinkPaths,
     FullLinkPaths,
 }
 }
 
 
-
 /// Whether to append file class characters to the file names.
 /// Whether to append file class characters to the file names.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum Classify {
 pub enum Classify {
-
     /// Just display the file names, without any characters.
     /// Just display the file names, without any characters.
     JustFilenames,
     JustFilenames,
 
 
@@ -80,7 +82,6 @@ impl Default for Classify {
 /// mount details, depending on how long the resulting Cell can be.
 /// mount details, depending on how long the resulting Cell can be.
 #[derive(PartialEq, Debug, Copy, Clone)]
 #[derive(PartialEq, Debug, Copy, Clone)]
 enum MountStyle {
 enum MountStyle {
-
     /// Just display the directory names.
     /// Just display the directory names.
     JustDirectoryNames,
     JustDirectoryNames,
 
 
@@ -92,7 +93,6 @@ enum MountStyle {
 /// Whether and how to show icons.
 /// Whether and how to show icons.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum ShowIcons {
 pub enum ShowIcons {
-
     /// Don’t show icons at all.
     /// Don’t show icons at all.
     Off,
     Off,
 
 
@@ -103,8 +103,7 @@ pub enum ShowIcons {
 
 
 /// Whether to embed hyperlinks.
 /// Whether to embed hyperlinks.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
-pub enum EmbedHyperlinks{
-    
+pub enum EmbedHyperlinks {
     Off,
     Off,
     On,
     On,
 }
 }
@@ -112,7 +111,6 @@ pub enum EmbedHyperlinks{
 /// 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, C> {
 pub struct FileName<'a, 'dir, C> {
-
     /// A reference to the file that we’re getting the name of.
     /// A reference to the file that we’re getting the name of.
     file: &'a File<'dir>,
     file: &'a File<'dir>,
 
 
@@ -120,7 +118,7 @@ pub struct FileName<'a, 'dir, C> {
     colours: &'a C,
     colours: &'a C,
 
 
     /// The file that this file points to if it’s a link.
     /// The file that this file points to if it’s a link.
-    target: Option<FileTarget<'dir>>,  // todo: remove?
+    target: Option<FileTarget<'dir>>, // todo: remove?
 
 
     /// How to handle displaying links.
     /// How to handle displaying links.
     link_style: LinkStyle,
     link_style: LinkStyle,
@@ -135,7 +133,6 @@ pub struct FileName<'a, 'dir, C> {
 }
 }
 
 
 impl<'a, 'dir, C> FileName<'a, 'dir, C> {
 impl<'a, 'dir, C> FileName<'a, 'dir, C> {
-
     /// Sets the flag on this file name to display link targets with an
     /// Sets the flag on this file name to display link targets with an
     /// arrow followed by their path.
     /// arrow followed by their path.
     pub fn with_link_paths(mut self) -> Self {
     pub fn with_link_paths(mut self) -> Self {
@@ -156,7 +153,6 @@ impl<'a, 'dir, C> FileName<'a, 'dir, C> {
 }
 }
 
 
 impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
 impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
-
     /// 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.
     ///
     ///
@@ -185,13 +181,13 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
             }
             }
         }
         }
 
 
-        if ! self.file.name.is_empty() {
-        	// The “missing file” colour seems like it should be used here,
-        	// but it’s not! In a grid view, where there’s no space to display
-        	// link targets, the filename has to have a different style to
-        	// indicate this fact. But when showing targets, we can just
-        	// colour the path instead (see below), and leave the broken
-        	// link’s filename as the link colour.
+        if !self.file.name.is_empty() {
+            // The “missing file” colour seems like it should be used here,
+            // but it’s not! In a grid view, where there’s no space to display
+            // link targets, the filename has to have a different style to
+            // indicate this fact. But when showing targets, we can just
+            // colour the path instead (see below), and leave the broken
+            // link’s filename as the link colour.
             for bit in self.escaped_file_name() {
             for bit in self.escaped_file_name() {
                 bits.push(bit);
                 bits.push(bit);
             }
             }
@@ -208,7 +204,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
                         self.add_parent_bits(&mut bits, parent);
                         self.add_parent_bits(&mut bits, parent);
                     }
                     }
 
 
-                    if ! target.name.is_empty() {
+                    if !target.name.is_empty() {
                         let target_options = Options {
                         let target_options = Options {
                             classify: Classify::JustFilenames,
                             classify: Classify::JustFilenames,
                             show_icons: ShowIcons::Off,
                             show_icons: ShowIcons::Off,
@@ -254,14 +250,15 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
                     // Do nothing — the error gets displayed on the next line
                     // Do nothing — the error gets displayed on the next line
                 }
                 }
             }
             }
-        }
-        else if let Classify::AddFileIndicators = self.options.classify {
+        } else if let Classify::AddFileIndicators = self.options.classify {
             if let Some(class) = self.classify_char(self.file) {
             if let Some(class) = self.classify_char(self.file) {
                 bits.push(Style::default().paint(class));
                 bits.push(Style::default().paint(class));
             }
             }
         }
         }
 
 
-        if let (MountStyle::MountInfo, Some(mount_details)) = (self.mount_style, self.mounted_fs.as_ref()) {
+        if let (MountStyle::MountInfo, Some(mount_details)) =
+            (self.mount_style, self.mounted_fs.as_ref())
+        {
             // This is a filesystem mounted on the directory, output its details
             // This is a filesystem mounted on the directory, output its details
             bits.push(Style::default().paint(" ["));
             bits.push(Style::default().paint(" ["));
             bits.push(Style::default().paint(mount_details.source.clone()));
             bits.push(Style::default().paint(mount_details.source.clone()));
@@ -279,16 +276,23 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
         let coconut = parent.components().count();
         let coconut = parent.components().count();
 
 
         if coconut == 1 && parent.has_root() {
         if coconut == 1 && parent.has_root() {
-            bits.push(self.colours.symlink_path().paint(std::path::MAIN_SEPARATOR.to_string()));
-        }
-        else if coconut >= 1 {
+            bits.push(
+                self.colours
+                    .symlink_path()
+                    .paint(std::path::MAIN_SEPARATOR.to_string()),
+            );
+        } else if coconut >= 1 {
             escape(
             escape(
                 parent.to_string_lossy().to_string(),
                 parent.to_string_lossy().to_string(),
                 bits,
                 bits,
                 self.colours.symlink_path(),
                 self.colours.symlink_path(),
                 self.colours.control_char(),
                 self.colours.control_char(),
             );
             );
-            bits.push(self.colours.symlink_path().paint(std::path::MAIN_SEPARATOR.to_string()));
+            bits.push(
+                self.colours
+                    .symlink_path()
+                    .paint(std::path::MAIN_SEPARATOR.to_string()),
+            );
         }
         }
     }
     }
 
 
@@ -298,20 +302,15 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
     fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
     fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
         if file.is_executable_file() {
         if file.is_executable_file() {
             Some("*")
             Some("*")
-        }
-        else if file.is_directory() {
+        } else if file.is_directory() {
             Some("/")
             Some("/")
-        }
-        else if file.is_pipe() {
+        } else if file.is_pipe() {
             Some("|")
             Some("|")
-        }
-        else if file.is_link() {
+        } else if file.is_link() {
             Some("@")
             Some("@")
-        }
-        else if file.is_socket() {
+        } else if file.is_socket() {
             Some("=")
             Some("=")
-        }
-        else {
+        } else {
             None
             None
         }
         }
     }
     }
@@ -320,11 +319,9 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
     fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
     fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
         if file.is_directory() {
         if file.is_directory() {
             Some("/")
             Some("/")
-        }
-        else if file.is_link() {
+        } else if file.is_link() {
             Some("@")
             Some("@")
-        }
-        else {
+        } else {
             None
             None
         }
         }
     }
     }
@@ -342,7 +339,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
     /// So in that situation, those characters will be escaped and highlighted in
     /// So in that situation, those characters will be escaped and highlighted in
     /// a different colour.
     /// a different colour.
     fn escaped_file_name<'unused>(&self) -> Vec<ANSIString<'unused>> {
     fn escaped_file_name<'unused>(&self) -> Vec<ANSIString<'unused>> {
-        use percent_encoding::{CONTROLS, utf8_percent_encode};
+        use percent_encoding::{utf8_percent_encode, CONTROLS};
 
 
         const HYPERLINK_START: &str = "\x1B]8;;";
         const HYPERLINK_START: &str = "\x1B]8;;";
         const HYPERLINK_END: &str = "\x1B\x5C";
         const HYPERLINK_END: &str = "\x1B\x5C";
@@ -352,7 +349,11 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
 
 
         let mut display_hyperlink = false;
         let mut display_hyperlink = false;
         if self.options.embed_hyperlinks == EmbedHyperlinks::On {
         if self.options.embed_hyperlinks == EmbedHyperlinks::On {
-            if let Some(abs_path) = self.file.absolute_path().and_then(|p| p.as_os_str().to_str()) {
+            if let Some(abs_path) = self
+                .file
+                .absolute_path()
+                .and_then(|p| p.as_os_str().to_str())
+            {
                 let abs_path = utf8_percent_encode(abs_path, CONTROLS).to_string();
                 let abs_path = utf8_percent_encode(abs_path, CONTROLS).to_string();
 
 
                 // On Windows, `std::fs::canonicalize` adds the Win32 File prefix, which we need to remove
                 // On Windows, `std::fs::canonicalize` adds the Win32 File prefix, which we need to remove
@@ -375,7 +376,9 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
         );
         );
 
 
         if display_hyperlink {
         if display_hyperlink {
-            bits.push(ANSIString::from(format!("{HYPERLINK_START}{HYPERLINK_END}")));
+            bits.push(ANSIString::from(format!(
+                "{HYPERLINK_START}{HYPERLINK_END}"
+            )));
         }
         }
 
 
         bits
         bits
@@ -394,7 +397,8 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
             }
             }
         }
         }
 
 
-        match self.file {
+        #[rustfmt::skip]
+        return match self.file {
             f if f.is_mount_point()      => self.colours.mount_point(),
             f if f.is_mount_point()      => self.colours.mount_point(),
             f if f.is_directory()        => self.colours.directory(),
             f if f.is_directory()        => self.colours.directory(),
             #[cfg(unix)]
             #[cfg(unix)]
@@ -410,7 +414,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
             f if f.is_socket()           => self.colours.socket(),
             f if f.is_socket()           => self.colours.socket(),
             f if ! f.is_file()           => self.colours.special(),
             f if ! f.is_file()           => self.colours.special(),
             _                            => self.colours.colour_file(self.file),
             _                            => self.colours.colour_file(self.file),
-        }
+        };
     }
     }
 
 
     /// For grid's use, to cover the case of hyperlink escape sequences
     /// For grid's use, to cover the case of hyperlink escape sequences
@@ -419,10 +423,8 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
     }
     }
 }
 }
 
 
-
 /// The set of colours that are needed to paint a file name.
 /// The set of colours that are needed to paint a file name.
 pub trait Colours: FiletypeColours {
 pub trait Colours: FiletypeColours {
-
     /// The style to paint the path of a symlink’s target, up to but not
     /// The style to paint the path of a symlink’s target, up to but not
     /// including the file’s name.
     /// including the file’s name.
     fn symlink_path(&self) -> Style;
     fn symlink_path(&self) -> Style;
@@ -430,9 +432,9 @@ pub trait Colours: FiletypeColours {
     /// The style to paint the arrow between a link and its target.
     /// The style to paint the arrow between a link and its target.
     fn normal_arrow(&self) -> Style;
     fn normal_arrow(&self) -> Style;
 
 
-	/// The style to paint the filenames of broken links in views that don’t
-	/// show link targets, and the style to paint the *arrow* between the link
-	/// and its target in views that *do* show link targets.
+    /// The style to paint the filenames of broken links in views that don’t
+    /// show link targets, and the style to paint the *arrow* between the link
+    /// and its target in views that *do* show link targets.
     fn broken_symlink(&self) -> Style;
     fn broken_symlink(&self) -> Style;
 
 
     /// The style to paint the entire filename of a broken link.
     /// The style to paint the entire filename of a broken link.
@@ -454,8 +456,7 @@ pub trait Colours: FiletypeColours {
     fn colour_file(&self, file: &File<'_>) -> Style;
     fn colour_file(&self, file: &File<'_>) -> Style;
 }
 }
 
 
-
 /// Generate a string made of `n` spaces.
 /// Generate a string made of `n` spaces.
 fn spaces(width: u32) -> String {
 fn spaces(width: u32) -> String {
-    (0 .. width).map(|_| ' ').collect()
+    (0..width).map(|_| ' ').collect()
 }
 }

+ 12 - 11
src/output/grid.rs

@@ -2,13 +2,12 @@ use std::io::{self, Write};
 
 
 use term_grid as tg;
 use term_grid as tg;
 
 
-use crate::fs::File;
 use crate::fs::filter::FileFilter;
 use crate::fs::filter::FileFilter;
+use crate::fs::File;
 use crate::output::file_name::Options as FileStyle;
 use crate::output::file_name::Options as FileStyle;
-use crate::output::file_name::{ShowIcons, EmbedHyperlinks};
+use crate::output::file_name::{EmbedHyperlinks, ShowIcons};
 use crate::theme::Theme;
 use crate::theme::Theme;
 
 
-
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub struct Options {
 pub struct Options {
     pub across: bool,
     pub across: bool,
@@ -16,12 +15,14 @@ pub struct Options {
 
 
 impl Options {
 impl Options {
     pub fn direction(self) -> tg::Direction {
     pub fn direction(self) -> tg::Direction {
-        if self.across { tg::Direction::LeftToRight }
-                  else { tg::Direction::TopToBottom }
+        if self.across {
+            tg::Direction::LeftToRight
+        } else {
+            tg::Direction::TopToBottom
+        }
     }
     }
 }
 }
 
 
-
 pub struct Render<'a> {
 pub struct Render<'a> {
     pub files: Vec<File<'a>>,
     pub files: Vec<File<'a>>,
     pub theme: &'a Theme,
     pub theme: &'a Theme,
@@ -34,8 +35,8 @@ pub struct Render<'a> {
 impl<'a> Render<'a> {
 impl<'a> Render<'a> {
     pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
     pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
         let mut grid = tg::Grid::new(tg::GridOptions {
         let mut grid = tg::Grid::new(tg::GridOptions {
-            direction:  self.opts.direction(),
-            filling:    tg::Filling::Spaces(2),
+            direction: self.opts.direction(),
+            filling: tg::Filling::Spaces(2),
         });
         });
 
 
         grid.reserve(self.files.len());
         grid.reserve(self.files.len());
@@ -44,6 +45,7 @@ impl<'a> Render<'a> {
         for file in &self.files {
         for file in &self.files {
             let filename = self.file_style.for_file(file, self.theme);
             let filename = self.file_style.for_file(file, self.theme);
             let contents = filename.paint();
             let contents = filename.paint();
+            #[rustfmt::skip]
             let width = match (filename.options.embed_hyperlinks, filename.options.show_icons) {
             let width = match (filename.options.embed_hyperlinks, filename.options.show_icons) {
                 (EmbedHyperlinks::On, ShowIcons::On(spacing)) => filename.bare_width() + 1 + (spacing as usize),
                 (EmbedHyperlinks::On, ShowIcons::On(spacing)) => filename.bare_width() + 1 + (spacing as usize),
                 (EmbedHyperlinks::On, ShowIcons::Off) => filename.bare_width(),
                 (EmbedHyperlinks::On, ShowIcons::Off) => filename.bare_width(),
@@ -51,7 +53,7 @@ impl<'a> Render<'a> {
             };
             };
 
 
             grid.add(tg::Cell {
             grid.add(tg::Cell {
-                contents:  contents.strings().to_string(),
+                contents: contents.strings().to_string(),
                 // with hyperlink escape sequences,
                 // with hyperlink escape sequences,
                 // the actual *contents.width() is larger than actually needed, so we take only the filename
                 // the actual *contents.width() is larger than actually needed, so we take only the filename
                 width,
                 width,
@@ -60,8 +62,7 @@ impl<'a> Render<'a> {
 
 
         if let Some(display) = grid.fit_into_width(self.console_width) {
         if let Some(display) = grid.fit_into_width(self.console_width) {
             write!(w, "{display}")
             write!(w, "{display}")
-        }
-        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!
             // This isn’t *quite* the same as the lines view, which also
             // This isn’t *quite* the same as the lines view, which also
             // displays full link paths.
             // displays full link paths.

+ 86 - 48
src/output/grid_details.rs

@@ -5,19 +5,20 @@ use std::io::{self, Write};
 use ansiterm::ANSIStrings;
 use ansiterm::ANSIStrings;
 use term_grid as grid;
 use term_grid as grid;
 
 
-use crate::fs::{Dir, File};
 use crate::fs::feature::git::GitCache;
 use crate::fs::feature::git::GitCache;
 use crate::fs::filter::FileFilter;
 use crate::fs::filter::FileFilter;
-use crate::output::cell::{TextCell, DisplayWidth};
-use crate::output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
+use crate::fs::{Dir, File};
+use crate::output::cell::{DisplayWidth, TextCell};
+use crate::output::details::{
+    Options as DetailsOptions, Render as DetailsRender, Row as DetailsRow,
+};
 use crate::output::file_name::Options as FileStyle;
 use crate::output::file_name::Options as FileStyle;
-use crate::output::file_name::{ShowIcons, EmbedHyperlinks};
+use crate::output::file_name::{EmbedHyperlinks, ShowIcons};
 use crate::output::grid::Options as GridOptions;
 use crate::output::grid::Options as GridOptions;
-use crate::output::table::{Table, Row as TableRow, Options as TableOptions};
-use crate::output::tree::{TreeParams, TreeDepth};
+use crate::output::table::{Options as TableOptions, Row as TableRow, Table};
+use crate::output::tree::{TreeDepth, TreeParams};
 use crate::theme::Theme;
 use crate::theme::Theme;
 
 
-
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub struct Options {
 pub struct Options {
     pub grid: GridOptions,
     pub grid: GridOptions,
@@ -31,7 +32,6 @@ impl Options {
     }
     }
 }
 }
 
 
-
 /// The grid-details view can be configured to revert to just a details view
 /// The grid-details view can be configured to revert to just a details view
 /// (with one column) if it wouldn’t produce enough rows of output.
 /// (with one column) if it wouldn’t produce enough rows of output.
 ///
 ///
@@ -41,7 +41,6 @@ impl Options {
 /// larger directory listings.
 /// larger directory listings.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum RowThreshold {
 pub enum RowThreshold {
-
     /// Only use grid-details view if it would result in at least this many
     /// Only use grid-details view if it would result in at least this many
     /// rows of output.
     /// rows of output.
     MinimumRows(usize),
     MinimumRows(usize),
@@ -50,9 +49,7 @@ pub enum RowThreshold {
     AlwaysGrid,
     AlwaysGrid,
 }
 }
 
 
-
 pub struct Render<'a> {
 pub struct Render<'a> {
-
     /// The directory that’s being rendered here.
     /// The directory that’s being rendered here.
     /// We need this to know which columns to put in the output.
     /// We need this to know which columns to put in the output.
     pub dir: Option<&'a Dir>,
     pub dir: Option<&'a Dir>,
@@ -91,7 +88,6 @@ pub struct Render<'a> {
 }
 }
 
 
 impl<'a> Render<'a> {
 impl<'a> Render<'a> {
-
     /// Create a temporary Details render that gets used for the columns of
     /// Create a temporary Details render that gets used for the columns of
     /// the grid-details render that’s being generated.
     /// the grid-details render that’s being generated.
     ///
     ///
@@ -99,7 +95,8 @@ impl<'a> Render<'a> {
     /// the table in *this* file, not in details: we only want to insert every
     /// the table in *this* file, not in details: we only want to insert every
     /// *n* files into each column’s table, not all of them.
     /// *n* files into each column’s table, not all of them.
     fn details_for_column(&self) -> DetailsRender<'a> {
     fn details_for_column(&self) -> DetailsRender<'a> {
-        DetailsRender {
+        #[rustfmt::skip]
+        return DetailsRender {
             dir:           self.dir,
             dir:           self.dir,
             files:         Vec::new(),
             files:         Vec::new(),
             theme:         self.theme,
             theme:         self.theme,
@@ -109,7 +106,7 @@ impl<'a> Render<'a> {
             filter:        self.filter,
             filter:        self.filter,
             git_ignoring:  self.git_ignoring,
             git_ignoring:  self.git_ignoring,
             git:           self.git,
             git:           self.git,
-        }
+        };
     }
     }
 
 
     /// Create a Details render for when this grid-details render doesn’t fit
     /// Create a Details render for when this grid-details render doesn’t fit
@@ -117,7 +114,8 @@ impl<'a> Render<'a> {
     /// when the user asked for a grid-details view but the terminal width is
     /// when the user asked for a grid-details view but the terminal width is
     /// not available, so we downgrade.
     /// not available, so we downgrade.
     pub fn give_up(self) -> DetailsRender<'a> {
     pub fn give_up(self) -> DetailsRender<'a> {
-        DetailsRender {
+        #[rustfmt::skip]
+        return DetailsRender {
             dir:           self.dir,
             dir:           self.dir,
             files:         self.files,
             files:         self.files,
             theme:         self.theme,
             theme:         self.theme,
@@ -127,7 +125,7 @@ impl<'a> Render<'a> {
             filter:        self.filter,
             filter:        self.filter,
             git_ignoring:  self.git_ignoring,
             git_ignoring:  self.git_ignoring,
             git:           self.git,
             git:           self.git,
-        }
+        };
     }
     }
 
 
     // This doesn’t take an IgnoreCache even though the details one does
     // This doesn’t take an IgnoreCache even though the details one does
@@ -136,27 +134,35 @@ impl<'a> Render<'a> {
     pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
     pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
         if let Some((grid, width)) = self.find_fitting_grid() {
         if let Some((grid, width)) = self.find_fitting_grid() {
             write!(w, "{}", grid.fit_into_columns(width))
             write!(w, "{}", grid.fit_into_columns(width))
-        }
-        else {
+        } else {
             self.give_up().render(w)
             self.give_up().render(w)
         }
         }
     }
     }
 
 
     pub fn find_fitting_grid(&mut self) -> Option<(grid::Grid, grid::Width)> {
     pub fn find_fitting_grid(&mut self) -> Option<(grid::Grid, grid::Width)> {
-        let options = self.details.table.as_ref().expect("Details table options not given!");
+        let options = self
+            .details
+            .table
+            .as_ref()
+            .expect("Details table options not given!");
 
 
         let drender = self.details_for_column();
         let drender = self.details_for_column();
 
 
         let (first_table, _) = self.make_table(options, &drender);
         let (first_table, _) = self.make_table(options, &drender);
 
 
-        let rows = self.files.iter()
-                       .map(|file| first_table.row_for_file(file, drender.show_xattr_hint(file)))
-                       .collect::<Vec<_>>();
+        let rows = self
+            .files
+            .iter()
+            .map(|file| first_table.row_for_file(file, drender.show_xattr_hint(file)))
+            .collect::<Vec<_>>();
 
 
-        let file_names = self.files.iter()
+        let file_names = self
+            .files
+            .iter()
             .map(|file| {
             .map(|file| {
                 let filename = self.file_style.for_file(file, self.theme);
                 let filename = self.file_style.for_file(file, self.theme);
                 let contents = filename.paint();
                 let contents = filename.paint();
+                #[rustfmt::skip]
                 let width = match (filename.options.embed_hyperlinks, filename.options.show_icons) {
                 let width = match (filename.options.embed_hyperlinks, filename.options.show_icons) {
                     (EmbedHyperlinks::On, ShowIcons::On(spacing)) => filename.bare_width() + 1 + (spacing as usize),
                     (EmbedHyperlinks::On, ShowIcons::On(spacing)) => filename.bare_width() + 1 + (spacing as usize),
                     (EmbedHyperlinks::On, ShowIcons::Off) => filename.bare_width(),
                     (EmbedHyperlinks::On, ShowIcons::Off) => filename.bare_width(),
@@ -193,12 +199,20 @@ impl<'a> Render<'a> {
             }
             }
 
 
             if !the_grid_fits || column_count == file_names.len() {
             if !the_grid_fits || column_count == file_names.len() {
-                let last_column_count = if the_grid_fits { column_count } else { column_count - 1 };
+                let last_column_count = if the_grid_fits {
+                    column_count
+                } else {
+                    column_count - 1
+                };
                 // If we’ve figured out how many columns can fit in the user’s terminal,
                 // If we’ve figured out how many columns can fit in the user’s terminal,
                 // and it turns out there aren’t enough rows to make it worthwhile
                 // and it turns out there aren’t enough rows to make it worthwhile
                 // (according to EZA_GRID_ROWS), then just resort to the lines view.
                 // (according to EZA_GRID_ROWS), then just resort to the lines view.
                 if let RowThreshold::MinimumRows(thresh) = self.row_threshold {
                 if let RowThreshold::MinimumRows(thresh) = self.row_threshold {
-                    if last_working_grid.fit_into_columns(last_column_count).row_count() < thresh {
+                    if last_working_grid
+                        .fit_into_columns(last_column_count)
+                        .row_count()
+                        < thresh
+                    {
                         return None;
                         return None;
                     }
                     }
                 }
                 }
@@ -210,11 +224,23 @@ impl<'a> Render<'a> {
         None
         None
     }
     }
 
 
-    fn make_table(&mut self, options: &'a TableOptions, drender: &DetailsRender<'_>) -> (Table<'a>, Vec<DetailsRow>) {
+    fn make_table(
+        &mut self,
+        options: &'a TableOptions,
+        drender: &DetailsRender<'_>,
+    ) -> (Table<'a>, Vec<DetailsRow>) {
         match (self.git, self.dir) {
         match (self.git, self.dir) {
-            (Some(g), Some(d))  => if ! g.has_anything_for(&d.path) { self.git = None },
-            (Some(g), None)     => if ! self.files.iter().any(|f| g.has_anything_for(&f.path)) { self.git = None },
-            (None,    _)        => {/* Keep Git how it is */},
+            (Some(g), Some(d)) => {
+                if !g.has_anything_for(&d.path) {
+                    self.git = None;
+                }
+            }
+            (Some(g), None) => {
+                if !self.files.iter().any(|f| g.has_anything_for(&f.path)) {
+                    self.git = None;
+                }
+            }
+            (None, _) => { /* Keep Git how it is */ }
         }
         }
 
 
         let mut table = Table::new(options, self.git, self.theme);
         let mut table = Table::new(options, self.git, self.theme);
@@ -229,9 +255,16 @@ impl<'a> Render<'a> {
         (table, rows)
         (table, rows)
     }
     }
 
 
-    fn make_grid(&mut self, column_count: usize, options: &'a TableOptions, file_names: &[TextCell], rows: Vec<TableRow>, drender: &DetailsRender<'_>) -> grid::Grid {
+    fn make_grid(
+        &mut self,
+        column_count: usize,
+        options: &'a TableOptions,
+        file_names: &[TextCell],
+        rows: Vec<TableRow>,
+        drender: &DetailsRender<'_>,
+    ) -> grid::Grid {
         let mut tables = Vec::new();
         let mut tables = Vec::new();
-        for _ in 0 .. column_count {
+        for _ in 0..column_count {
             tables.push(self.make_table(options, drender));
             tables.push(self.make_table(options, drender));
         }
         }
 
 
@@ -245,52 +278,58 @@ impl<'a> Render<'a> {
 
 
         for (i, (file_name, row)) in file_names.iter().zip(rows).enumerate() {
         for (i, (file_name, row)) in file_names.iter().zip(rows).enumerate() {
             let index = if self.grid.across {
             let index = if self.grid.across {
-                    i % column_count
-                }
-                else {
-                    i / original_height
-                };
+                i % column_count
+            } else {
+                i / original_height
+            };
 
 
             let (ref mut table, ref mut rows) = tables[index];
             let (ref mut table, ref mut rows) = tables[index];
             table.add_widths(&row);
             table.add_widths(&row);
-            let details_row = drender.render_file(row, file_name.clone(), TreeParams::new(TreeDepth::root(), false));
+            let details_row = drender.render_file(
+                row,
+                file_name.clone(),
+                TreeParams::new(TreeDepth::root(), false),
+            );
             rows.push(details_row);
             rows.push(details_row);
         }
         }
 
 
         let columns = tables
         let columns = tables
             .into_iter()
             .into_iter()
             .map(|(table, details_rows)| {
             .map(|(table, details_rows)| {
-                drender.iterate_with_table(table, details_rows)
-                       .collect::<Vec<_>>()
-                })
+                drender
+                    .iterate_with_table(table, details_rows)
+                    .collect::<Vec<_>>()
+            })
             .collect::<Vec<_>>();
             .collect::<Vec<_>>();
 
 
-        let direction = if self.grid.across { grid::Direction::LeftToRight }
-                                       else { grid::Direction::TopToBottom };
+        let direction = if self.grid.across {
+            grid::Direction::LeftToRight
+        } else {
+            grid::Direction::TopToBottom
+        };
 
 
         let filling = grid::Filling::Spaces(4);
         let filling = grid::Filling::Spaces(4);
         let mut grid = grid::Grid::new(grid::GridOptions { direction, filling });
         let mut grid = grid::Grid::new(grid::GridOptions { direction, filling });
 
 
         if self.grid.across {
         if self.grid.across {
-            for row in 0 .. height {
+            for row in 0..height {
                 for column in &columns {
                 for column in &columns {
                     if row < column.len() {
                     if row < column.len() {
                         let cell = grid::Cell {
                         let cell = grid::Cell {
                             contents: ANSIStrings(&column[row].contents).to_string(),
                             contents: ANSIStrings(&column[row].contents).to_string(),
-                            width:    *column[row].width,
+                            width: *column[row].width,
                         };
                         };
 
 
                         grid.add(cell);
                         grid.add(cell);
                     }
                     }
                 }
                 }
             }
             }
-        }
-        else {
+        } else {
             for column in &columns {
             for column in &columns {
                 for cell in column {
                 for cell in column {
                     let cell = grid::Cell {
                     let cell = grid::Cell {
                         contents: ANSIStrings(&cell.contents).to_string(),
                         contents: ANSIStrings(&cell.contents).to_string(),
-                        width:    *cell.width,
+                        width: *cell.width,
                     };
                     };
 
 
                     grid.add(cell);
                     grid.add(cell);
@@ -302,7 +341,6 @@ impl<'a> Render<'a> {
     }
     }
 }
 }
 
 
-
 fn divide_rounding_up(a: usize, b: usize) -> usize {
 fn divide_rounding_up(a: usize, b: usize) -> usize {
     let mut result = a / b;
     let mut result = a / b;
 
 

+ 6 - 3
src/output/icons.rs

@@ -6,6 +6,7 @@ use crate::fs::File;
 #[non_exhaustive]
 #[non_exhaustive]
 struct Icons;
 struct Icons;
 
 
+#[rustfmt::skip]
 impl Icons {
 impl Icons {
     const AUDIO: char           = '\u{f001}';  // 
     const AUDIO: char           = '\u{f001}';  // 
     const BINARY: char          = '\u{eae8}';  // 
     const BINARY: char          = '\u{eae8}';  // 
@@ -703,9 +704,11 @@ const EXTENSION_ICONS: Map<&'static str, char> = phf_map! {
 /// - Attributes such as bold or underline should not be used to paint the
 /// - Attributes such as bold or underline should not be used to paint the
 ///   icon, as they can make it look weird.
 ///   icon, as they can make it look weird.
 pub fn iconify_style(style: Style) -> Style {
 pub fn iconify_style(style: Style) -> Style {
-    style.background.or(style.foreground)
-         .map(Style::from)
-         .unwrap_or_default()
+    style
+        .background
+        .or(style.foreground)
+        .map(Style::from)
+        .unwrap_or_default()
 }
 }
 
 
 /// Lookup the icon for a file based on the file's name, if the entry is a
 /// Lookup the icon for a file based on the file's name, if the entry is a

+ 1 - 2
src/output/lines.rs

@@ -2,13 +2,12 @@ use std::io::{self, Write};
 
 
 use ansiterm::ANSIStrings;
 use ansiterm::ANSIStrings;
 
 
-use crate::fs::File;
 use crate::fs::filter::FileFilter;
 use crate::fs::filter::FileFilter;
+use crate::fs::File;
 use crate::output::cell::TextCellContents;
 use crate::output::cell::TextCellContents;
 use crate::output::file_name::Options as FileStyle;
 use crate::output::file_name::Options as FileStyle;
 use crate::theme::Theme;
 use crate::theme::Theme;
 
 
-
 /// The lines view literally just displays each file, line-by-line.
 /// The lines view literally just displays each file, line-by-line.
 pub struct Render<'a> {
 pub struct Render<'a> {
     pub files: Vec<File<'a>>,
     pub files: Vec<File<'a>>,

+ 4 - 7
src/output/mod.rs

@@ -1,4 +1,4 @@
-pub use self::cell::{TextCell, TextCellContents, DisplayWidth};
+pub use self::cell::{DisplayWidth, TextCell, TextCellContents};
 pub use self::escape::escape;
 pub use self::escape::escape;
 
 
 pub mod details;
 pub mod details;
@@ -15,7 +15,6 @@ mod cell;
 mod escape;
 mod escape;
 mod tree;
 mod tree;
 
 
-
 /// The **view** contains all information about how to format output.
 /// The **view** contains all information about how to format output.
 #[derive(Debug)]
 #[derive(Debug)]
 pub struct View {
 pub struct View {
@@ -25,7 +24,6 @@ pub struct View {
     pub deref_links: bool,
     pub deref_links: bool,
 }
 }
 
 
-
 /// The **mode** is the “type” of output.
 /// The **mode** is the “type” of output.
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 #[allow(clippy::large_enum_variant)]
 #[allow(clippy::large_enum_variant)]
@@ -36,11 +34,9 @@ pub enum Mode {
     Lines,
     Lines,
 }
 }
 
 
-
 /// The width of the terminal requested by the user.
 /// The width of the terminal requested by the user.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum TerminalWidth {
 pub enum TerminalWidth {
-
     /// The user requested this specific number of columns.
     /// The user requested this specific number of columns.
     Set(usize),
     Set(usize),
 
 
@@ -54,9 +50,10 @@ impl TerminalWidth {
         // terminal, but we’re only interested in stdout because it’s
         // terminal, but we’re only interested in stdout because it’s
         // where the output goes.
         // where the output goes.
 
 
-        match self {
+        #[rustfmt::skip]
+        return match self {
             Self::Set(width)  => Some(width),
             Self::Set(width)  => Some(width),
             Self::Automatic   => terminal_size::terminal_size().map(|(w, _)| w.0.into()),
             Self::Automatic   => terminal_size::terminal_size().map(|(w, _)| w.0.into()),
-        }
+        };
     }
     }
 }
 }

+ 60 - 38
src/output/render/blocks.rs

@@ -3,28 +3,31 @@ use locale::Numeric as NumericLocale;
 use number_prefix::Prefix;
 use number_prefix::Prefix;
 
 
 use crate::fs::fields as f;
 use crate::fs::fields as f;
-use crate::output::cell::{TextCell, DisplayWidth};
+use crate::output::cell::{DisplayWidth, TextCell};
 use crate::output::table::SizeFormat;
 use crate::output::table::SizeFormat;
 
 
-
 impl f::Blocksize {
 impl f::Blocksize {
-    pub fn render<C: Colours>(self, colours: &C, size_format: SizeFormat, numerics: &NumericLocale) -> TextCell {
+    pub fn render<C: Colours>(
+        self,
+        colours: &C,
+        size_format: SizeFormat,
+        numerics: &NumericLocale,
+    ) -> TextCell {
         use number_prefix::NumberPrefix;
         use number_prefix::NumberPrefix;
 
 
         let size = match self {
         let size = match self {
-            Self::Some(s)             => s,
-            Self::None                => return TextCell::blank(colours.no_blocksize()),
+            Self::Some(s) => s,
+            Self::None => return TextCell::blank(colours.no_blocksize()),
         };
         };
 
 
         let result = match size_format {
         let result = match size_format {
-            SizeFormat::DecimalBytes  => NumberPrefix::decimal(size as f64),
-            SizeFormat::BinaryBytes   => NumberPrefix::binary(size as f64),
-            SizeFormat::JustBytes     => {
-
+            SizeFormat::DecimalBytes => NumberPrefix::decimal(size as f64),
+            SizeFormat::BinaryBytes => NumberPrefix::binary(size as f64),
+            SizeFormat::JustBytes => {
                 // Use the binary prefix to select a style.
                 // Use the binary prefix to select a style.
                 let prefix = match NumberPrefix::binary(size as f64) {
                 let prefix = match NumberPrefix::binary(size as f64) {
-                    NumberPrefix::Standalone(_)   => None,
-                    NumberPrefix::Prefixed(p, _)  => Some(p),
+                    NumberPrefix::Standalone(_) => None,
+                    NumberPrefix::Prefixed(p, _) => Some(p),
                 };
                 };
 
 
                 // But format the number directly using the locale.
                 // But format the number directly using the locale.
@@ -35,8 +38,10 @@ impl f::Blocksize {
         };
         };
 
 
         let (prefix, n) = match result {
         let (prefix, n) = match result {
-            NumberPrefix::Standalone(b)   => return TextCell::paint(colours.blocksize(None), numerics.format_int(b)),
-            NumberPrefix::Prefixed(p, n)  => (p, n),
+            NumberPrefix::Standalone(b) => {
+                return TextCell::paint(colours.blocksize(None), numerics.format_int(b))
+            }
+            NumberPrefix::Prefixed(p, n) => (p, n),
         };
         };
 
 
         let symbol = prefix.symbol();
         let symbol = prefix.symbol();
@@ -52,89 +57,106 @@ impl f::Blocksize {
             contents: vec![
             contents: vec![
                 colours.blocksize(Some(prefix)).paint(number),
                 colours.blocksize(Some(prefix)).paint(number),
                 colours.unit(Some(prefix)).paint(symbol),
                 colours.unit(Some(prefix)).paint(symbol),
-            ].into(),
+            ]
+            .into(),
         }
         }
     }
     }
 }
 }
 
 
-
+#[rustfmt::skip]
 pub trait Colours {
 pub trait Colours {
     fn blocksize(&self, prefix: Option<Prefix>) -> Style;
     fn blocksize(&self, prefix: Option<Prefix>) -> Style;
     fn unit(&self, prefix: Option<Prefix>)      -> Style;
     fn unit(&self, prefix: Option<Prefix>)      -> Style;
     fn no_blocksize(&self)                      -> Style;
     fn no_blocksize(&self)                      -> Style;
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 pub mod test {
 pub mod test {
-    use ansiterm::Style;
     use ansiterm::Colour::*;
     use ansiterm::Colour::*;
+    use ansiterm::Style;
 
 
     use super::Colours;
     use super::Colours;
-    use crate::output::cell::{TextCell, DisplayWidth};
-    use crate::output::table::SizeFormat;
     use crate::fs::fields as f;
     use crate::fs::fields as f;
+    use crate::output::cell::{DisplayWidth, TextCell};
+    use crate::output::table::SizeFormat;
 
 
     use locale::Numeric as NumericLocale;
     use locale::Numeric as NumericLocale;
     use number_prefix::Prefix;
     use number_prefix::Prefix;
 
 
     struct TestColours;
     struct TestColours;
 
 
+    #[rustfmt::skip]
     impl Colours for TestColours {
     impl Colours for TestColours {
         fn blocksize(&self, _prefix: Option<Prefix>) -> Style { Fixed(66).normal() }
         fn blocksize(&self, _prefix: Option<Prefix>) -> Style { Fixed(66).normal() }
         fn unit(&self, _prefix: Option<Prefix>)      -> Style { Fixed(77).bold() }
         fn unit(&self, _prefix: Option<Prefix>)      -> Style { Fixed(77).bold() }
         fn no_blocksize(&self)                       -> Style { Black.italic() }
         fn no_blocksize(&self)                       -> Style { Black.italic() }
     }
     }
 
 
-
     #[test]
     #[test]
     fn directory() {
     fn directory() {
         let directory = f::Blocksize::None;
         let directory = f::Blocksize::None;
         let expected = TextCell::blank(Black.italic());
         let expected = TextCell::blank(Black.italic());
-        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
+        assert_eq!(
+            expected,
+            directory.render(
+                &TestColours,
+                SizeFormat::JustBytes,
+                &NumericLocale::english()
+            )
+        )
     }
     }
 
 
-
     #[test]
     #[test]
     fn file_decimal() {
     fn file_decimal() {
         let directory = f::Blocksize::Some(2_100_000);
         let directory = f::Blocksize::Some(2_100_000);
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(4),
             width: DisplayWidth::from(4),
-            contents: vec![
-                Fixed(66).paint("2.1"),
-                Fixed(77).bold().paint("M"),
-            ].into(),
+            contents: vec![Fixed(66).paint("2.1"), Fixed(77).bold().paint("M")].into(),
         };
         };
 
 
-        assert_eq!(expected, directory.render(&TestColours, SizeFormat::DecimalBytes, &NumericLocale::english()))
+        assert_eq!(
+            expected,
+            directory.render(
+                &TestColours,
+                SizeFormat::DecimalBytes,
+                &NumericLocale::english()
+            )
+        )
     }
     }
 
 
-
     #[test]
     #[test]
     fn file_binary() {
     fn file_binary() {
         let directory = f::Blocksize::Some(1_048_576);
         let directory = f::Blocksize::Some(1_048_576);
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(5),
             width: DisplayWidth::from(5),
-            contents: vec![
-                Fixed(66).paint("1.0"),
-                Fixed(77).bold().paint("Mi"),
-            ].into(),
+            contents: vec![Fixed(66).paint("1.0"), Fixed(77).bold().paint("Mi")].into(),
         };
         };
 
 
-        assert_eq!(expected, directory.render(&TestColours, SizeFormat::BinaryBytes, &NumericLocale::english()))
+        assert_eq!(
+            expected,
+            directory.render(
+                &TestColours,
+                SizeFormat::BinaryBytes,
+                &NumericLocale::english()
+            )
+        )
     }
     }
 
 
-
     #[test]
     #[test]
     fn file_bytes() {
     fn file_bytes() {
         let directory = f::Blocksize::Some(1_048_576);
         let directory = f::Blocksize::Some(1_048_576);
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(9),
             width: DisplayWidth::from(9),
-            contents: vec![
-                Fixed(66).paint("1,048,576"),
-            ].into(),
+            contents: vec![Fixed(66).paint("1,048,576")].into(),
         };
         };
 
 
-        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
+        assert_eq!(
+            expected,
+            directory.render(
+                &TestColours,
+                SizeFormat::JustBytes,
+                &NumericLocale::english()
+            )
+        )
     }
     }
 }
 }

+ 3 - 4
src/output/render/filetype.rs

@@ -2,10 +2,10 @@ use ansiterm::{ANSIString, Style};
 
 
 use crate::fs::fields as f;
 use crate::fs::fields as f;
 
 
-
 impl f::Type {
 impl f::Type {
     pub fn render<C: Colours>(self, colours: &C) -> ANSIString<'static> {
     pub fn render<C: Colours>(self, colours: &C) -> ANSIString<'static> {
-        match self {
+        #[rustfmt::skip]
+        return match self {
             Self::File         => colours.normal().paint("."),
             Self::File         => colours.normal().paint("."),
             Self::Directory    => colours.directory().paint("d"),
             Self::Directory    => colours.directory().paint("d"),
             Self::Pipe         => colours.pipe().paint("|"),
             Self::Pipe         => colours.pipe().paint("|"),
@@ -14,11 +14,10 @@ impl f::Type {
             Self::CharDevice   => colours.char_device().paint("c"),
             Self::CharDevice   => colours.char_device().paint("c"),
             Self::Socket       => colours.socket().paint("s"),
             Self::Socket       => colours.socket().paint("s"),
             Self::Special      => colours.special().paint("?"),
             Self::Special      => colours.special().paint("?"),
-        }
+        };
     }
     }
 }
 }
 
 
-
 pub trait Colours {
 pub trait Colours {
     fn normal(&self) -> Style;
     fn normal(&self) -> Style;
     fn directory(&self) -> Style;
     fn directory(&self) -> Style;

+ 43 - 37
src/output/render/git.rs

@@ -1,24 +1,21 @@
 use ansiterm::{ANSIString, Style};
 use ansiterm::{ANSIString, Style};
 
 
-use crate::output::cell::{TextCell, DisplayWidth};
 use crate::fs::fields as f;
 use crate::fs::fields as f;
-
+use crate::output::cell::{DisplayWidth, TextCell};
 
 
 impl f::Git {
 impl f::Git {
     pub fn render(self, colours: &dyn Colours) -> TextCell {
     pub fn render(self, colours: &dyn Colours) -> TextCell {
         TextCell {
         TextCell {
             width: DisplayWidth::from(2),
             width: DisplayWidth::from(2),
-            contents: vec![
-                self.staged.render(colours),
-                self.unstaged.render(colours),
-            ].into(),
+            contents: vec![self.staged.render(colours), self.unstaged.render(colours)].into(),
         }
         }
     }
     }
 }
 }
 
 
 impl f::GitStatus {
 impl f::GitStatus {
     fn render(self, colours: &dyn Colours) -> ANSIString<'static> {
     fn render(self, colours: &dyn Colours) -> ANSIString<'static> {
-        match self {
+        #[rustfmt::skip]
+        return match self {
             Self::NotModified  => colours.not_modified().paint("-"),
             Self::NotModified  => colours.not_modified().paint("-"),
             Self::New          => colours.new().paint("N"),
             Self::New          => colours.new().paint("N"),
             Self::Modified     => colours.modified().paint("M"),
             Self::Modified     => colours.modified().paint("M"),
@@ -27,7 +24,7 @@ impl f::GitStatus {
             Self::TypeChange   => colours.type_change().paint("T"),
             Self::TypeChange   => colours.type_change().paint("T"),
             Self::Ignored      => colours.ignored().paint("I"),
             Self::Ignored      => colours.ignored().paint("I"),
             Self::Conflicted   => colours.conflicted().paint("U"),
             Self::Conflicted   => colours.conflicted().paint("U"),
-        }
+        };
     }
     }
 }
 }
 
 
@@ -35,7 +32,7 @@ pub trait Colours {
     fn not_modified(&self) -> Style;
     fn not_modified(&self) -> Style;
     // FIXME: this amount of allows needed to keep clippy happy should be enough
     // FIXME: this amount of allows needed to keep clippy happy should be enough
     // of an argument that new needs to be renamed.
     // of an argument that new needs to be renamed.
-    #[allow(clippy::new_ret_no_self,clippy::wrong_self_convention)]
+    #[allow(clippy::new_ret_no_self, clippy::wrong_self_convention)]
     fn new(&self) -> Style;
     fn new(&self) -> Style;
     fn modified(&self) -> Style;
     fn modified(&self) -> Style;
     fn deleted(&self) -> Style;
     fn deleted(&self) -> Style;
@@ -45,14 +42,16 @@ pub trait Colours {
     fn conflicted(&self) -> Style;
     fn conflicted(&self) -> Style;
 }
 }
 
 
-
 impl f::SubdirGitRepo {
 impl f::SubdirGitRepo {
     pub fn render(self, colours: &dyn RepoColours) -> TextCell {
     pub fn render(self, colours: &dyn RepoColours) -> TextCell {
         let branch_name = match self.branch {
         let branch_name = match self.branch {
             Some(name) => {
             Some(name) => {
-                if name == "main" || name == "master" { colours.branch_main().paint(name) }
-                else { colours.branch_other().paint(name) }
-            },
+                if name == "main" || name == "master" {
+                    colours.branch_main().paint(name)
+                } else {
+                    colours.branch_other().paint(name)
+                }
+            }
             None => colours.no_repo().paint("-"),
             None => colours.no_repo().paint("-"),
         };
         };
 
 
@@ -63,7 +62,8 @@ impl f::SubdirGitRepo {
                     status.render(colours),
                     status.render(colours),
                     Style::default().paint(" "),
                     Style::default().paint(" "),
                     branch_name,
                     branch_name,
-                ].into(),
+                ]
+                .into(),
             }
             }
         } else {
         } else {
             TextCell {
             TextCell {
@@ -92,63 +92,69 @@ pub trait RepoColours {
     fn git_dirty(&self) -> Style;
     fn git_dirty(&self) -> Style;
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 pub mod test {
 pub mod test {
     use super::Colours;
     use super::Colours;
-    use crate::output::cell::{TextCell, DisplayWidth};
     use crate::fs::fields as f;
     use crate::fs::fields as f;
+    use crate::output::cell::{DisplayWidth, TextCell};
 
 
     use ansiterm::Colour::*;
     use ansiterm::Colour::*;
     use ansiterm::Style;
     use ansiterm::Style;
 
 
-
     struct TestColours;
     struct TestColours;
 
 
     impl Colours for TestColours {
     impl Colours for TestColours {
-        fn not_modified(&self) -> Style { Fixed(90).normal() }
-        fn new(&self)          -> Style { Fixed(91).normal() }
-        fn modified(&self)     -> Style { Fixed(92).normal() }
-        fn deleted(&self)      -> Style { Fixed(93).normal() }
-        fn renamed(&self)      -> Style { Fixed(94).normal() }
-        fn type_change(&self)  -> Style { Fixed(95).normal() }
-        fn ignored(&self)      -> Style { Fixed(96).normal() }
-        fn conflicted(&self)   -> Style { Fixed(97).normal() }
+        fn not_modified(&self) -> Style {
+            Fixed(90).normal()
+        }
+        fn new(&self) -> Style {
+            Fixed(91).normal()
+        }
+        fn modified(&self) -> Style {
+            Fixed(92).normal()
+        }
+        fn deleted(&self) -> Style {
+            Fixed(93).normal()
+        }
+        fn renamed(&self) -> Style {
+            Fixed(94).normal()
+        }
+        fn type_change(&self) -> Style {
+            Fixed(95).normal()
+        }
+        fn ignored(&self) -> Style {
+            Fixed(96).normal()
+        }
+        fn conflicted(&self) -> Style {
+            Fixed(97).normal()
+        }
     }
     }
 
 
-
     #[test]
     #[test]
     fn git_blank() {
     fn git_blank() {
         let stati = f::Git {
         let stati = f::Git {
-            staged:   f::GitStatus::NotModified,
+            staged: f::GitStatus::NotModified,
             unstaged: f::GitStatus::NotModified,
             unstaged: f::GitStatus::NotModified,
         };
         };
 
 
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(2),
             width: DisplayWidth::from(2),
-            contents: vec![
-                Fixed(90).paint("-"),
-                Fixed(90).paint("-"),
-            ].into(),
+            contents: vec![Fixed(90).paint("-"), Fixed(90).paint("-")].into(),
         };
         };
 
 
         assert_eq!(expected, stati.render(&TestColours))
         assert_eq!(expected, stati.render(&TestColours))
     }
     }
 
 
-
     #[test]
     #[test]
     fn git_new_changed() {
     fn git_new_changed() {
         let stati = f::Git {
         let stati = f::Git {
-            staged:   f::GitStatus::New,
+            staged: f::GitStatus::New,
             unstaged: f::GitStatus::Modified,
             unstaged: f::GitStatus::Modified,
         };
         };
 
 
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(2),
             width: DisplayWidth::from(2),
-            contents: vec![
-                Fixed(91).paint("N"),
-                Fixed(92).paint("M"),
-            ].into(),
+            contents: vec![Fixed(91).paint("N"), Fixed(92).paint("M")].into(),
         };
         };
 
 
         assert_eq!(expected, stati.render(&TestColours))
         assert_eq!(expected, stati.render(&TestColours))

+ 52 - 23
src/output/render/groups.rs

@@ -1,16 +1,26 @@
 use ansiterm::Style;
 use ansiterm::Style;
-use uzers::{Users, Groups};
+use uzers::{Groups, Users};
 
 
 use crate::fs::fields as f;
 use crate::fs::fields as f;
 use crate::output::cell::TextCell;
 use crate::output::cell::TextCell;
 use crate::output::table::UserFormat;
 use crate::output::table::UserFormat;
 
 
-pub trait Render{
-    fn render<C: Colours, U: Users+Groups>(self, colours: &C, users: &U, format: UserFormat) -> TextCell;
+pub trait Render {
+    fn render<C: Colours, U: Users + Groups>(
+        self,
+        colours: &C,
+        users: &U,
+        format: UserFormat,
+    ) -> TextCell;
 }
 }
 
 
 impl Render for Option<f::Group> {
 impl Render for Option<f::Group> {
-    fn render<C: Colours, U: Users+Groups>(self, colours: &C, users: &U, format: UserFormat) -> TextCell {
+    fn render<C: Colours, U: Users + Groups>(
+        self,
+        colours: &C,
+        users: &U,
+        format: UserFormat,
+    ) -> TextCell {
         use uzers::os::unix::GroupExt;
         use uzers::os::unix::GroupExt;
 
 
         let mut style = colours.not_yours();
         let mut style = colours.not_yours();
@@ -18,17 +28,15 @@ impl Render for Option<f::Group> {
         let group = match self {
         let group = match self {
             Some(g) => match users.get_group_by_gid(g.0) {
             Some(g) => match users.get_group_by_gid(g.0) {
                 Some(g) => (*g).clone(),
                 Some(g) => (*g).clone(),
-                None    => return TextCell::paint(style, g.0.to_string()),
+                None => return TextCell::paint(style, g.0.to_string()),
             },
             },
             None => return TextCell::blank(colours.no_group()),
             None => return TextCell::blank(colours.no_group()),
         };
         };
 
 
-
         let current_uid = users.get_current_uid();
         let current_uid = users.get_current_uid();
         if let Some(current_user) = users.get_user_by_uid(current_uid) {
         if let Some(current_user) = users.get_user_by_uid(current_uid) {
-
             if current_user.primary_group_id() == group.gid()
             if current_user.primary_group_id() == group.gid()
-            || group.members().iter().any(|u| u == current_user.name())
+                || group.members().iter().any(|u| u == current_user.name())
             {
             {
                 style = colours.yours();
                 style = colours.yours();
             }
             }
@@ -43,14 +51,12 @@ impl Render for Option<f::Group> {
     }
     }
 }
 }
 
 
-
 pub trait Colours {
 pub trait Colours {
     fn yours(&self) -> Style;
     fn yours(&self) -> Style;
     fn not_yours(&self) -> Style;
     fn not_yours(&self) -> Style;
     fn no_group(&self) -> Style;
     fn no_group(&self) -> Style;
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 #[allow(unused_results)]
 #[allow(unused_results)]
 pub mod test {
 pub mod test {
@@ -59,22 +65,21 @@ pub mod test {
     use crate::output::cell::TextCell;
     use crate::output::cell::TextCell;
     use crate::output::table::UserFormat;
     use crate::output::table::UserFormat;
 
 
-    use uzers::{User, Group};
-    use uzers::mock::MockUsers;
-    use uzers::os::unix::GroupExt;
     use ansiterm::Colour::*;
     use ansiterm::Colour::*;
     use ansiterm::Style;
     use ansiterm::Style;
-
+    use uzers::mock::MockUsers;
+    use uzers::os::unix::GroupExt;
+    use uzers::{Group, User};
 
 
     struct TestColours;
     struct TestColours;
 
 
+    #[rustfmt::skip]
     impl Colours for TestColours {
     impl Colours for TestColours {
         fn yours(&self)     -> Style { Fixed(80).normal() }
         fn yours(&self)     -> Style { Fixed(80).normal() }
         fn not_yours(&self) -> Style { Fixed(81).normal() }
         fn not_yours(&self) -> Style { Fixed(81).normal() }
         fn no_group(&self)   -> Style { Black.italic() }
         fn no_group(&self)   -> Style { Black.italic() }
     }
     }
 
 
-
     #[test]
     #[test]
     fn named() {
     fn named() {
         let mut users = MockUsers::with_current_uid(1000);
         let mut users = MockUsers::with_current_uid(1000);
@@ -82,21 +87,32 @@ pub mod test {
 
 
         let group = Some(f::Group(100));
         let group = Some(f::Group(100));
         let expected = TextCell::paint_str(Fixed(81).normal(), "folk");
         let expected = TextCell::paint_str(Fixed(81).normal(), "folk");
-        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Name));
+        assert_eq!(
+            expected,
+            group.render(&TestColours, &users, UserFormat::Name)
+        );
 
 
         let expected = TextCell::paint_str(Fixed(81).normal(), "100");
         let expected = TextCell::paint_str(Fixed(81).normal(), "100");
-        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Numeric));
+        assert_eq!(
+            expected,
+            group.render(&TestColours, &users, UserFormat::Numeric)
+        );
     }
     }
 
 
-
     #[test]
     #[test]
     fn unnamed() {
     fn unnamed() {
         let users = MockUsers::with_current_uid(1000);
         let users = MockUsers::with_current_uid(1000);
 
 
         let group = Some(f::Group(100));
         let group = Some(f::Group(100));
         let expected = TextCell::paint_str(Fixed(81).normal(), "100");
         let expected = TextCell::paint_str(Fixed(81).normal(), "100");
-        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Name));
-        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Numeric));
+        assert_eq!(
+            expected,
+            group.render(&TestColours, &users, UserFormat::Name)
+        );
+        assert_eq!(
+            expected,
+            group.render(&TestColours, &users, UserFormat::Numeric)
+        );
     }
     }
 
 
     #[test]
     #[test]
@@ -107,7 +123,10 @@ pub mod test {
 
 
         let group = Some(f::Group(100));
         let group = Some(f::Group(100));
         let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
         let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
-        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Name))
+        assert_eq!(
+            expected,
+            group.render(&TestColours, &users, UserFormat::Name)
+        )
     }
     }
 
 
     #[test]
     #[test]
@@ -120,13 +139,23 @@ pub mod test {
 
 
         let group = Some(f::Group(100));
         let group = Some(f::Group(100));
         let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
         let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
-        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Name))
+        assert_eq!(
+            expected,
+            group.render(&TestColours, &users, UserFormat::Name)
+        )
     }
     }
 
 
     #[test]
     #[test]
     fn overflow() {
     fn overflow() {
         let group = Some(f::Group(2_147_483_648));
         let group = Some(f::Group(2_147_483_648));
         let expected = TextCell::paint_str(Fixed(81).normal(), "2147483648");
         let expected = TextCell::paint_str(Fixed(81).normal(), "2147483648");
-        assert_eq!(expected, group.render(&TestColours, &MockUsers::with_current_uid(0), UserFormat::Numeric));
+        assert_eq!(
+            expected,
+            group.render(
+                &TestColours,
+                &MockUsers::with_current_uid(0),
+                UserFormat::Numeric
+            )
+        );
     }
     }
 }
 }

+ 1 - 4
src/output/render/inode.rs

@@ -3,22 +3,19 @@ use ansiterm::Style;
 use crate::fs::fields as f;
 use crate::fs::fields as f;
 use crate::output::cell::TextCell;
 use crate::output::cell::TextCell;
 
 
-
 impl f::Inode {
 impl f::Inode {
     pub fn render(self, style: Style) -> TextCell {
     pub fn render(self, style: Style) -> TextCell {
         TextCell::paint(style, self.0.to_string())
         TextCell::paint(style, self.0.to_string())
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 pub mod test {
 pub mod test {
-    use crate::output::cell::TextCell;
     use crate::fs::fields as f;
     use crate::fs::fields as f;
+    use crate::output::cell::TextCell;
 
 
     use ansiterm::Colour::*;
     use ansiterm::Colour::*;
 
 
-
     #[test]
     #[test]
     fn blocklessness() {
     fn blocklessness() {
         let io = f::Inode(1_414_213);
         let io = f::Inode(1_414_213);

+ 31 - 19
src/output/render/links.rs

@@ -10,87 +10,99 @@ use crate::output::cell::TextCell;
 #[cfg(unix)]
 #[cfg(unix)]
 impl f::Links {
 impl f::Links {
     pub fn render<C: Colours>(&self, colours: &C, numeric: &NumericLocale) -> TextCell {
     pub fn render<C: Colours>(&self, colours: &C, numeric: &NumericLocale) -> TextCell {
-        let style = if self.multiple { colours.multi_link_file() }
-                                else { colours.normal() };
+        let style = if self.multiple {
+            colours.multi_link_file()
+        } else {
+            colours.normal()
+        };
 
 
         TextCell::paint(style, numeric.format_int(self.count))
         TextCell::paint(style, numeric.format_int(self.count))
     }
     }
 }
 }
 
 
-
 pub trait Colours {
 pub trait Colours {
     fn normal(&self) -> Style;
     fn normal(&self) -> Style;
     fn multi_link_file(&self) -> Style;
     fn multi_link_file(&self) -> Style;
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 pub mod test {
 pub mod test {
     use super::Colours;
     use super::Colours;
-    #[cfg(unix)]   
-    use crate::output::cell::{TextCell, DisplayWidth};
     #[cfg(unix)]
     #[cfg(unix)]
     use crate::fs::fields as f;
     use crate::fs::fields as f;
+    #[cfg(unix)]
+    use crate::output::cell::{DisplayWidth, TextCell};
 
 
     use ansiterm::Colour::*;
     use ansiterm::Colour::*;
     use ansiterm::Style;
     use ansiterm::Style;
     #[cfg(unix)]
     #[cfg(unix)]
     use locale;
     use locale;
 
 
-
     struct TestColours;
     struct TestColours;
 
 
     impl Colours for TestColours {
     impl Colours for TestColours {
-        fn normal(&self)           -> Style { Blue.normal() }
-        fn multi_link_file(&self)  -> Style { Blue.on(Red) }
+        fn normal(&self) -> Style {
+            Blue.normal()
+        }
+        fn multi_link_file(&self) -> Style {
+            Blue.on(Red)
+        }
     }
     }
 
 
-
     #[test]
     #[test]
     #[cfg(unix)]
     #[cfg(unix)]
     fn regular_file() {
     fn regular_file() {
         let stati = f::Links {
         let stati = f::Links {
-            count:    1,
+            count: 1,
             multiple: false,
             multiple: false,
         };
         };
 
 
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(1),
             width: DisplayWidth::from(1),
-            contents: vec![ Blue.paint("1") ].into(),
+            contents: vec![Blue.paint("1")].into(),
         };
         };
 
 
-        assert_eq!(expected, stati.render(&TestColours, &locale::Numeric::english()));
+        assert_eq!(
+            expected,
+            stati.render(&TestColours, &locale::Numeric::english())
+        );
     }
     }
 
 
     #[test]
     #[test]
     #[cfg(unix)]
     #[cfg(unix)]
     fn regular_directory() {
     fn regular_directory() {
         let stati = f::Links {
         let stati = f::Links {
-            count:    3005,
+            count: 3005,
             multiple: false,
             multiple: false,
         };
         };
 
 
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(5),
             width: DisplayWidth::from(5),
-            contents: vec![ Blue.paint("3,005") ].into(),
+            contents: vec![Blue.paint("3,005")].into(),
         };
         };
 
 
-        assert_eq!(expected, stati.render(&TestColours, &locale::Numeric::english()));
+        assert_eq!(
+            expected,
+            stati.render(&TestColours, &locale::Numeric::english())
+        );
     }
     }
 
 
     #[test]
     #[test]
     #[cfg(unix)]
     #[cfg(unix)]
     fn popular_file() {
     fn popular_file() {
         let stati = f::Links {
         let stati = f::Links {
-            count:    3005,
+            count: 3005,
             multiple: true,
             multiple: true,
         };
         };
 
 
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(5),
             width: DisplayWidth::from(5),
-            contents: vec![ Blue.on(Red).paint("3,005") ].into(),
+            contents: vec![Blue.on(Red).paint("3,005")].into(),
         };
         };
 
 
-        assert_eq!(expected, stati.render(&TestColours, &locale::Numeric::english()));
+        assert_eq!(
+            expected,
+            stati.render(&TestColours, &locale::Numeric::english())
+        );
     }
     }
 }
 }

+ 107 - 36
src/output/render/octal.rs

@@ -12,14 +12,34 @@ impl Render for Option<f::OctalPermissions> {
         match self {
         match self {
             Some(p) => {
             Some(p) => {
                 let perm = &p.permissions;
                 let perm = &p.permissions;
-                let octal_sticky = f::OctalPermissions::bits_to_octal(perm.setuid, perm.setgid, perm.sticky);
-                let octal_owner  = f::OctalPermissions::bits_to_octal(perm.user_read, perm.user_write, perm.user_execute);
-                let octal_group  = f::OctalPermissions::bits_to_octal(perm.group_read, perm.group_write, perm.group_execute);
-                let octal_other  = f::OctalPermissions::bits_to_octal(perm.other_read, perm.other_write, perm.other_execute);
-
-                TextCell::paint(style, format!("{octal_sticky}{octal_owner}{octal_group}{octal_other}"))
-            },
-            None => TextCell::paint(style, "----".into())
+                #[rustfmt::skip]
+                let octal_sticky = f::OctalPermissions::bits_to_octal(
+                    perm.setuid,
+                    perm.setgid,
+                    perm.sticky
+                );
+                let octal_owner = f::OctalPermissions::bits_to_octal(
+                    perm.user_read,
+                    perm.user_write,
+                    perm.user_execute,
+                );
+                let octal_group = f::OctalPermissions::bits_to_octal(
+                    perm.group_read,
+                    perm.group_write,
+                    perm.group_execute,
+                );
+                let octal_other = f::OctalPermissions::bits_to_octal(
+                    perm.other_read,
+                    perm.other_write,
+                    perm.other_execute,
+                );
+
+                TextCell::paint(
+                    style,
+                    format!("{octal_sticky}{octal_owner}{octal_group}{octal_other}"),
+                )
+            }
+            None => TextCell::paint(style, "----".into()),
         }
         }
     }
     }
 }
 }
@@ -30,25 +50,32 @@ impl f::OctalPermissions {
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 pub mod test {
 pub mod test {
     use super::Render;
     use super::Render;
-    use crate::output::cell::TextCell;
     use crate::fs::fields as f;
     use crate::fs::fields as f;
+    use crate::output::cell::TextCell;
 
 
     use ansiterm::Colour::*;
     use ansiterm::Colour::*;
 
 
-
     #[test]
     #[test]
     fn normal_folder() {
     fn normal_folder() {
         let bits = f::Permissions {
         let bits = f::Permissions {
-            user_read:  true, user_write:  true,  user_execute:  true, setuid: false,
-            group_read: true, group_write: false, group_execute: true, setgid: false,
-            other_read: true, other_write: false, other_execute: true, sticky: false,
+            user_read: true,
+            user_write: true,
+            user_execute: true,
+            setuid: false,
+            group_read: true,
+            group_write: false,
+            group_execute: true,
+            setgid: false,
+            other_read: true,
+            other_write: false,
+            other_execute: true,
+            sticky: false,
         };
         };
 
 
-        let octal = Some(f::OctalPermissions{ permissions: bits });
+        let octal = Some(f::OctalPermissions { permissions: bits });
 
 
         let expected = TextCell::paint_str(Purple.bold(), "0755");
         let expected = TextCell::paint_str(Purple.bold(), "0755");
         assert_eq!(expected, octal.render(Purple.bold()));
         assert_eq!(expected, octal.render(Purple.bold()));
@@ -57,12 +84,21 @@ pub mod test {
     #[test]
     #[test]
     fn normal_file() {
     fn normal_file() {
         let bits = f::Permissions {
         let bits = f::Permissions {
-            user_read:  true, user_write:  true,  user_execute:  false, setuid: false,
-            group_read: true, group_write: false, group_execute: false, setgid: false,
-            other_read: true, other_write: false, other_execute: false, sticky: false,
+            user_read: true,
+            user_write: true,
+            user_execute: false,
+            setuid: false,
+            group_read: true,
+            group_write: false,
+            group_execute: false,
+            setgid: false,
+            other_read: true,
+            other_write: false,
+            other_execute: false,
+            sticky: false,
         };
         };
 
 
-        let octal = Some(f::OctalPermissions{ permissions: bits });
+        let octal = Some(f::OctalPermissions { permissions: bits });
 
 
         let expected = TextCell::paint_str(Purple.bold(), "0644");
         let expected = TextCell::paint_str(Purple.bold(), "0644");
         assert_eq!(expected, octal.render(Purple.bold()));
         assert_eq!(expected, octal.render(Purple.bold()));
@@ -71,12 +107,21 @@ pub mod test {
     #[test]
     #[test]
     fn secret_file() {
     fn secret_file() {
         let bits = f::Permissions {
         let bits = f::Permissions {
-            user_read:  true,  user_write:  true,  user_execute:  false, setuid: false,
-            group_read: false, group_write: false, group_execute: false, setgid: false,
-            other_read: false, other_write: false, other_execute: false, sticky: false,
+            user_read: true,
+            user_write: true,
+            user_execute: false,
+            setuid: false,
+            group_read: false,
+            group_write: false,
+            group_execute: false,
+            setgid: false,
+            other_read: false,
+            other_write: false,
+            other_execute: false,
+            sticky: false,
         };
         };
 
 
-        let octal = Some(f::OctalPermissions{ permissions: bits });
+        let octal = Some(f::OctalPermissions { permissions: bits });
 
 
         let expected = TextCell::paint_str(Purple.bold(), "0600");
         let expected = TextCell::paint_str(Purple.bold(), "0600");
         assert_eq!(expected, octal.render(Purple.bold()));
         assert_eq!(expected, octal.render(Purple.bold()));
@@ -85,27 +130,44 @@ pub mod test {
     #[test]
     #[test]
     fn sticky1() {
     fn sticky1() {
         let bits = f::Permissions {
         let bits = f::Permissions {
-            user_read:  true, user_write:  true,  user_execute:  true, setuid: true,
-            group_read: true, group_write: true,  group_execute: true, setgid: false,
-            other_read: true, other_write: true,  other_execute: true, sticky: false,
+            user_read: true,
+            user_write: true,
+            user_execute: true,
+            setuid: true,
+            group_read: true,
+            group_write: true,
+            group_execute: true,
+            setgid: false,
+            other_read: true,
+            other_write: true,
+            other_execute: true,
+            sticky: false,
         };
         };
 
 
-        let octal = Some(f::OctalPermissions{ permissions: bits });
+        let octal = Some(f::OctalPermissions { permissions: bits });
 
 
         let expected = TextCell::paint_str(Purple.bold(), "4777");
         let expected = TextCell::paint_str(Purple.bold(), "4777");
         assert_eq!(expected, octal.render(Purple.bold()));
         assert_eq!(expected, octal.render(Purple.bold()));
-
     }
     }
 
 
     #[test]
     #[test]
     fn sticky2() {
     fn sticky2() {
         let bits = f::Permissions {
         let bits = f::Permissions {
-            user_read:  true, user_write:  true,  user_execute:  true, setuid: false,
-            group_read: true, group_write: true,  group_execute: true, setgid: true,
-            other_read: true, other_write: true,  other_execute: true, sticky: false,
+            user_read: true,
+            user_write: true,
+            user_execute: true,
+            setuid: false,
+            group_read: true,
+            group_write: true,
+            group_execute: true,
+            setgid: true,
+            other_read: true,
+            other_write: true,
+            other_execute: true,
+            sticky: false,
         };
         };
 
 
-        let octal = Some(f::OctalPermissions{ permissions: bits });
+        let octal = Some(f::OctalPermissions { permissions: bits });
 
 
         let expected = TextCell::paint_str(Purple.bold(), "2777");
         let expected = TextCell::paint_str(Purple.bold(), "2777");
         assert_eq!(expected, octal.render(Purple.bold()));
         assert_eq!(expected, octal.render(Purple.bold()));
@@ -114,12 +176,21 @@ pub mod test {
     #[test]
     #[test]
     fn sticky3() {
     fn sticky3() {
         let bits = f::Permissions {
         let bits = f::Permissions {
-            user_read:  true, user_write:  true,  user_execute:  true, setuid: false,
-            group_read: true, group_write: true,  group_execute: true, setgid: false,
-            other_read: true, other_write: true,  other_execute: true, sticky: true,
+            user_read: true,
+            user_write: true,
+            user_execute: true,
+            setuid: false,
+            group_read: true,
+            group_write: true,
+            group_execute: true,
+            setgid: false,
+            other_read: true,
+            other_write: true,
+            other_execute: true,
+            sticky: true,
         };
         };
 
 
-        let octal = Some(f::OctalPermissions{ permissions: bits });
+        let octal = Some(f::OctalPermissions { permissions: bits });
 
 
         let expected = TextCell::paint_str(Purple.bold(), "1777");
         let expected = TextCell::paint_str(Purple.bold(), "1777");
         assert_eq!(expected, octal.render(Purple.bold()));
         assert_eq!(expected, octal.render(Purple.bold()));

+ 141 - 78
src/output/render/permissions.rs

@@ -3,38 +3,38 @@ use std::iter;
 use ansiterm::{ANSIString, Style};
 use ansiterm::{ANSIString, Style};
 
 
 use crate::fs::fields as f;
 use crate::fs::fields as f;
-use crate::output::cell::{TextCell, DisplayWidth};
+use crate::output::cell::{DisplayWidth, TextCell};
 use crate::output::render::FiletypeColours;
 use crate::output::render::FiletypeColours;
 
 
 pub trait PermissionsPlusRender {
 pub trait PermissionsPlusRender {
-    fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell;
+    fn render<C: Colours + FiletypeColours>(&self, colours: &C) -> TextCell;
 }
 }
 
 
 impl PermissionsPlusRender for Option<f::PermissionsPlus> {
 impl PermissionsPlusRender for Option<f::PermissionsPlus> {
     #[cfg(unix)]
     #[cfg(unix)]
-    fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
+    fn render<C: Colours + FiletypeColours>(&self, colours: &C) -> TextCell {
         match self {
         match self {
             Some(p) => {
             Some(p) => {
-                let mut chars = vec![ p.file_type.render(colours) ];
+                let mut chars = vec![p.file_type.render(colours)];
                 let permissions = p.permissions;
                 let permissions = p.permissions;
                 chars.extend(Some(permissions).render(colours, p.file_type.is_regular_file()));
                 chars.extend(Some(permissions).render(colours, p.file_type.is_regular_file()));
 
 
                 if p.xattrs {
                 if p.xattrs {
-                   chars.push(colours.attribute().paint("@"));
+                    chars.push(colours.attribute().paint("@"));
                 }
                 }
 
 
                 // As these are all ASCII characters, we can guarantee that they’re
                 // As these are all ASCII characters, we can guarantee that they’re
                 // all going to be one character wide, and don’t need to compute the
                 // all going to be one character wide, and don’t need to compute the
                 // cell’s display width.
                 // cell’s display width.
                 TextCell {
                 TextCell {
-                    width:    DisplayWidth::from(chars.len()),
+                    width: DisplayWidth::from(chars.len()),
                     contents: chars.into(),
                     contents: chars.into(),
                 }
                 }
-            },
+            }
             None => {
             None => {
                 let chars: Vec<_> = iter::repeat(colours.dash().paint("-")).take(10).collect();
                 let chars: Vec<_> = iter::repeat(colours.dash().paint("-")).take(10).collect();
                 TextCell {
                 TextCell {
-                    width:    DisplayWidth::from(chars.len()),
+                    width: DisplayWidth::from(chars.len()),
                     contents: chars.into(),
                     contents: chars.into(),
                 }
                 }
             }
             }
@@ -42,23 +42,21 @@ impl PermissionsPlusRender for Option<f::PermissionsPlus> {
     }
     }
 
 
     #[cfg(windows)]
     #[cfg(windows)]
-    fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
+    fn render<C: Colours + FiletypeColours>(&self, colours: &C) -> TextCell {
         match self {
         match self {
             Some(p) => {
             Some(p) => {
-                let mut chars = vec![ p.attributes.render_type(colours) ];
+                let mut chars = vec![p.attributes.render_type(colours)];
                 chars.extend(p.attributes.render(colours));
                 chars.extend(p.attributes.render(colours));
 
 
                 TextCell {
                 TextCell {
-                    width:    DisplayWidth::from(chars.len()),
+                    width: DisplayWidth::from(chars.len()),
                     contents: chars.into(),
                     contents: chars.into(),
-                }        
-            },
-            None => {
-                TextCell {
-                    width:    DisplayWidth::from(0),
-                    contents: vec![].into(),
-                }        
+                }
             }
             }
+            None => TextCell {
+                width: DisplayWidth::from(0),
+                contents: vec![].into(),
+            },
         }
         }
     }
     }
 }
 }
@@ -72,82 +70,92 @@ impl RenderPermissions for Option<f::Permissions> {
         match self {
         match self {
             Some(p) => {
             Some(p) => {
                 let bit = |bit, chr: &'static str, style: Style| {
                 let bit = |bit, chr: &'static str, style: Style| {
-                    if bit { style.paint(chr) }
-                      else { colours.dash().paint("-") }
+                    if bit {
+                        style.paint(chr)
+                    } else {
+                        colours.dash().paint("-")
+                    }
                 };
                 };
 
 
                 vec![
                 vec![
-                    bit(p.user_read,   "r", colours.user_read()),
-                    bit(p.user_write,  "w", colours.user_write()),
+                    bit(p.user_read, "r", colours.user_read()),
+                    bit(p.user_write, "w", colours.user_write()),
                     p.user_execute_bit(colours, is_regular_file),
                     p.user_execute_bit(colours, is_regular_file),
-                    bit(p.group_read,  "r", colours.group_read()),
+                    bit(p.group_read, "r", colours.group_read()),
                     bit(p.group_write, "w", colours.group_write()),
                     bit(p.group_write, "w", colours.group_write()),
                     p.group_execute_bit(colours),
                     p.group_execute_bit(colours),
-                    bit(p.other_read,  "r", colours.other_read()),
+                    bit(p.other_read, "r", colours.other_read()),
                     bit(p.other_write, "w", colours.other_write()),
                     bit(p.other_write, "w", colours.other_write()),
-                    p.other_execute_bit(colours)
+                    p.other_execute_bit(colours),
                 ]
                 ]
-            },
-            None => {
-                iter::repeat(colours.dash().paint("-")).take(9).collect()
             }
             }
+            None => iter::repeat(colours.dash().paint("-")).take(9).collect(),
         }
         }
     }
     }
 }
 }
 
 
 impl f::Permissions {
 impl f::Permissions {
-    fn user_execute_bit<C: Colours>(&self, colours: &C, is_regular_file: bool) -> ANSIString<'static> {
-        match (self.user_execute, self.setuid, is_regular_file) {
+    fn user_execute_bit<C: Colours>(
+        &self,
+        colours: &C,
+        is_regular_file: bool,
+    ) -> ANSIString<'static> {
+        #[rustfmt::skip]
+        return match (self.user_execute, self.setuid, is_regular_file) {
             (false, false, _)      => colours.dash().paint("-"),
             (false, false, _)      => colours.dash().paint("-"),
             (true,  false, false)  => colours.user_execute_other().paint("x"),
             (true,  false, false)  => colours.user_execute_other().paint("x"),
             (true,  false, true)   => colours.user_execute_file().paint("x"),
             (true,  false, true)   => colours.user_execute_file().paint("x"),
             (false, true,  _)      => colours.special_other().paint("S"),
             (false, true,  _)      => colours.special_other().paint("S"),
             (true,  true,  false)  => colours.special_other().paint("s"),
             (true,  true,  false)  => colours.special_other().paint("s"),
             (true,  true,  true)   => colours.special_user_file().paint("s"),
             (true,  true,  true)   => colours.special_user_file().paint("s"),
-        }
+        };
     }
     }
 
 
     fn group_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
     fn group_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
-        match (self.group_execute, self.setgid) {
+        #[rustfmt::skip]
+        return match (self.group_execute, self.setgid) {
             (false, false)  => colours.dash().paint("-"),
             (false, false)  => colours.dash().paint("-"),
             (true,  false)  => colours.group_execute().paint("x"),
             (true,  false)  => colours.group_execute().paint("x"),
             (false, true)   => colours.special_other().paint("S"),
             (false, true)   => colours.special_other().paint("S"),
             (true,  true)   => colours.special_other().paint("s"),
             (true,  true)   => colours.special_other().paint("s"),
-        }
+        };
     }
     }
 
 
     fn other_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
     fn other_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
-        match (self.other_execute, self.sticky) {
+        #[rustfmt::skip]
+        return match (self.other_execute, self.sticky) {
             (false, false)  => colours.dash().paint("-"),
             (false, false)  => colours.dash().paint("-"),
             (true,  false)  => colours.other_execute().paint("x"),
             (true,  false)  => colours.other_execute().paint("x"),
             (false, true)   => colours.special_other().paint("T"),
             (false, true)   => colours.special_other().paint("T"),
             (true,  true)   => colours.special_other().paint("t"),
             (true,  true)   => colours.special_other().paint("t"),
-        }
+        };
     }
     }
 }
 }
 
 
 #[cfg(windows)]
 #[cfg(windows)]
 impl f::Attributes {
 impl f::Attributes {
-    pub fn render<C: Colours+FiletypeColours>(self, colours: &C) -> Vec<ANSIString<'static>> {
+    pub fn render<C: Colours + FiletypeColours>(self, colours: &C) -> Vec<ANSIString<'static>> {
         let bit = |bit, chr: &'static str, style: Style| {
         let bit = |bit, chr: &'static str, style: Style| {
-            if bit { style.paint(chr) }
-              else { colours.dash().paint("-") }
+            if bit {
+                style.paint(chr)
+            } else {
+                colours.dash().paint("-")
+            }
         };
         };
 
 
         vec![
         vec![
-            bit(self.archive,   "a", colours.normal()),
-            bit(self.readonly,  "r", colours.user_read()),
-            bit(self.hidden,    "h", colours.special_user_file()),
-            bit(self.system,    "s", colours.special_other()),
+            bit(self.archive, "a", colours.normal()),
+            bit(self.readonly, "r", colours.user_read()),
+            bit(self.hidden, "h", colours.special_user_file()),
+            bit(self.system, "s", colours.special_other()),
         ]
         ]
     }
     }
 
 
-    pub fn render_type<C: Colours+FiletypeColours>(self, colours: &C) -> ANSIString<'static> {
+    pub fn render_type<C: Colours + FiletypeColours>(self, colours: &C) -> ANSIString<'static> {
         if self.reparse_point {
         if self.reparse_point {
-            return colours.pipe().paint("l")
-        }
-        else if self.directory {
-            return colours.directory().paint("d")
+            return colours.pipe().paint("l");
+        } else if self.directory {
+            return colours.directory().paint("d");
         }
         }
         colours.dash().paint("-")
         colours.dash().paint("-")
     }
     }
@@ -175,20 +183,19 @@ pub trait Colours {
     fn attribute(&self) -> Style;
     fn attribute(&self) -> Style;
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 #[allow(unused_results)]
 #[allow(unused_results)]
 pub mod test {
 pub mod test {
     use super::{Colours, RenderPermissions};
     use super::{Colours, RenderPermissions};
-    use crate::output::cell::TextCellContents;
     use crate::fs::fields as f;
     use crate::fs::fields as f;
+    use crate::output::cell::TextCellContents;
 
 
     use ansiterm::Colour::*;
     use ansiterm::Colour::*;
     use ansiterm::Style;
     use ansiterm::Style;
 
 
-
     struct TestColours;
     struct TestColours;
 
 
+    #[rustfmt::skip]
     impl Colours for TestColours {
     impl Colours for TestColours {
         fn dash(&self)                -> Style { Fixed(11).normal() }
         fn dash(&self)                -> Style { Fixed(11).normal() }
         fn user_read(&self)           -> Style { Fixed(101).normal() }
         fn user_read(&self)           -> Style { Fixed(101).normal() }
@@ -206,73 +213,129 @@ pub mod test {
         fn attribute(&self)           -> Style { Fixed(112).normal() }
         fn attribute(&self)           -> Style { Fixed(112).normal() }
     }
     }
 
 
-
     #[test]
     #[test]
     fn negate() {
     fn negate() {
         let bits = Some(f::Permissions {
         let bits = Some(f::Permissions {
-            user_read:  false,  user_write:  false,  user_execute:  false,  setuid: false,
-            group_read: false,  group_write: false,  group_execute: false,  setgid: false,
-            other_read: false,  other_write: false,  other_execute: false,  sticky: false,
+            user_read: false,
+            user_write: false,
+            user_execute: false,
+            setuid: false,
+            group_read: false,
+            group_write: false,
+            group_execute: false,
+            setgid: false,
+            other_read: false,
+            other_write: false,
+            other_execute: false,
+            sticky: false,
         });
         });
 
 
         let expected = TextCellContents::from(vec![
         let expected = TextCellContents::from(vec![
-            Fixed(11).paint("-"),  Fixed(11).paint("-"),  Fixed(11).paint("-"),
-            Fixed(11).paint("-"),  Fixed(11).paint("-"),  Fixed(11).paint("-"),
-            Fixed(11).paint("-"),  Fixed(11).paint("-"),  Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
         ]);
         ]);
 
 
         assert_eq!(expected, bits.render(&TestColours, false).into())
         assert_eq!(expected, bits.render(&TestColours, false).into())
     }
     }
 
 
-
     #[test]
     #[test]
     fn affirm() {
     fn affirm() {
         let bits = Some(f::Permissions {
         let bits = Some(f::Permissions {
-            user_read:  true,  user_write:  true,  user_execute:  true,  setuid: false,
-            group_read: true,  group_write: true,  group_execute: true,  setgid: false,
-            other_read: true,  other_write: true,  other_execute: true,  sticky: false,
+            user_read: true,
+            user_write: true,
+            user_execute: true,
+            setuid: false,
+            group_read: true,
+            group_write: true,
+            group_execute: true,
+            setgid: false,
+            other_read: true,
+            other_write: true,
+            other_execute: true,
+            sticky: false,
         });
         });
 
 
         let expected = TextCellContents::from(vec![
         let expected = TextCellContents::from(vec![
-            Fixed(101).paint("r"),  Fixed(102).paint("w"),  Fixed(103).paint("x"),
-            Fixed(104).paint("r"),  Fixed(105).paint("w"),  Fixed(106).paint("x"),
-            Fixed(107).paint("r"),  Fixed(108).paint("w"),  Fixed(109).paint("x"),
+            Fixed(101).paint("r"),
+            Fixed(102).paint("w"),
+            Fixed(103).paint("x"),
+            Fixed(104).paint("r"),
+            Fixed(105).paint("w"),
+            Fixed(106).paint("x"),
+            Fixed(107).paint("r"),
+            Fixed(108).paint("w"),
+            Fixed(109).paint("x"),
         ]);
         ]);
 
 
         assert_eq!(expected, bits.render(&TestColours, true).into())
         assert_eq!(expected, bits.render(&TestColours, true).into())
     }
     }
 
 
-
     #[test]
     #[test]
     fn specials() {
     fn specials() {
         let bits = Some(f::Permissions {
         let bits = Some(f::Permissions {
-            user_read:  false,  user_write:  false,  user_execute:  true,  setuid: true,
-            group_read: false,  group_write: false,  group_execute: true,  setgid: true,
-            other_read: false,  other_write: false,  other_execute: true,  sticky: true,
+            user_read: false,
+            user_write: false,
+            user_execute: true,
+            setuid: true,
+            group_read: false,
+            group_write: false,
+            group_execute: true,
+            setgid: true,
+            other_read: false,
+            other_write: false,
+            other_execute: true,
+            sticky: true,
         });
         });
 
 
         let expected = TextCellContents::from(vec![
         let expected = TextCellContents::from(vec![
-            Fixed(11).paint("-"),  Fixed(11).paint("-"),  Fixed(110).paint("s"),
-            Fixed(11).paint("-"),  Fixed(11).paint("-"),  Fixed(111).paint("s"),
-            Fixed(11).paint("-"),  Fixed(11).paint("-"),  Fixed(111).paint("t"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(110).paint("s"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(111).paint("s"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(111).paint("t"),
         ]);
         ]);
 
 
         assert_eq!(expected, bits.render(&TestColours, true).into())
         assert_eq!(expected, bits.render(&TestColours, true).into())
     }
     }
 
 
-
     #[test]
     #[test]
     fn extra_specials() {
     fn extra_specials() {
         let bits = Some(f::Permissions {
         let bits = Some(f::Permissions {
-            user_read:  false,  user_write:  false,  user_execute:  false,  setuid: true,
-            group_read: false,  group_write: false,  group_execute: false,  setgid: true,
-            other_read: false,  other_write: false,  other_execute: false,  sticky: true,
+            user_read: false,
+            user_write: false,
+            user_execute: false,
+            setuid: true,
+            group_read: false,
+            group_write: false,
+            group_execute: false,
+            setgid: true,
+            other_read: false,
+            other_write: false,
+            other_execute: false,
+            sticky: true,
         });
         });
 
 
         let expected = TextCellContents::from(vec![
         let expected = TextCellContents::from(vec![
-            Fixed(11).paint("-"),  Fixed(11).paint("-"),  Fixed(111).paint("S"),
-            Fixed(11).paint("-"),  Fixed(11).paint("-"),  Fixed(111).paint("S"),
-            Fixed(11).paint("-"),  Fixed(11).paint("-"),  Fixed(111).paint("T"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(111).paint("S"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(111).paint("S"),
+            Fixed(11).paint("-"),
+            Fixed(11).paint("-"),
+            Fixed(111).paint("T"),
         ]);
         ]);
 
 
         assert_eq!(expected, bits.render(&TestColours, true).into())
         assert_eq!(expected, bits.render(&TestColours, true).into())

+ 6 - 8
src/output/render/securityctx.rs

@@ -1,15 +1,12 @@
 use ansiterm::Style;
 use ansiterm::Style;
 
 
 use crate::fs::fields as f;
 use crate::fs::fields as f;
-use crate::output::cell::{TextCell, DisplayWidth};
-
+use crate::output::cell::{DisplayWidth, TextCell};
 
 
 impl f::SecurityContext<'_> {
 impl f::SecurityContext<'_> {
     pub fn render<C: Colours>(&self, colours: &C) -> TextCell {
     pub fn render<C: Colours>(&self, colours: &C) -> TextCell {
         match &self.context {
         match &self.context {
-            f::SecurityContextType::None => {
-                TextCell::paint_str(colours.none(), "?")
-            }
+            f::SecurityContextType::None => TextCell::paint_str(colours.none(), "?"),
             f::SecurityContextType::SELinux(context) => {
             f::SecurityContextType::SELinux(context) => {
                 let mut chars = Vec::with_capacity(7);
                 let mut chars = Vec::with_capacity(7);
 
 
@@ -18,7 +15,7 @@ impl f::SecurityContext<'_> {
                         0 => colours.selinux_user(),
                         0 => colours.selinux_user(),
                         1 => colours.selinux_role(),
                         1 => colours.selinux_role(),
                         2 => colours.selinux_type(),
                         2 => colours.selinux_type(),
-                        _ => colours.selinux_range()
+                        _ => colours.selinux_range(),
                     };
                     };
                     if i > 0 {
                     if i > 0 {
                         chars.push(colours.selinux_colon().paint(":"));
                         chars.push(colours.selinux_colon().paint(":"));
@@ -28,15 +25,16 @@ impl f::SecurityContext<'_> {
 
 
                 TextCell {
                 TextCell {
                     contents: chars.into(),
                     contents: chars.into(),
-                    width: DisplayWidth::from(context.len())
+                    width: DisplayWidth::from(context.len()),
                 }
                 }
             }
             }
         }
         }
     }
     }
 }
 }
 
 
+#[rustfmt::skip]
 pub trait Colours {
 pub trait Colours {
-    fn none(&self)          -> Style;
+    fn none(&self) -> Style;
     fn selinux_colon(&self) -> Style;
     fn selinux_colon(&self) -> Style;
     fn selinux_user(&self)  -> Style;
     fn selinux_user(&self)  -> Style;
     fn selinux_role(&self)  -> Style;
     fn selinux_role(&self)  -> Style;

+ 70 - 39
src/output/render/size.rs

@@ -3,20 +3,25 @@ use locale::Numeric as NumericLocale;
 use number_prefix::Prefix;
 use number_prefix::Prefix;
 
 
 use crate::fs::fields as f;
 use crate::fs::fields as f;
-use crate::output::cell::{TextCell, DisplayWidth};
+use crate::output::cell::{DisplayWidth, TextCell};
 use crate::output::table::SizeFormat;
 use crate::output::table::SizeFormat;
 
 
-
 impl f::Size {
 impl f::Size {
-    pub fn render<C: Colours>(self, colours: &C, size_format: SizeFormat, numerics: &NumericLocale) -> TextCell {
+    pub fn render<C: Colours>(
+        self,
+        colours: &C,
+        size_format: SizeFormat,
+        numerics: &NumericLocale,
+    ) -> TextCell {
         use number_prefix::NumberPrefix;
         use number_prefix::NumberPrefix;
 
 
         let size = match self {
         let size = match self {
-            Self::Some(s)             => s,
-            Self::None                => return TextCell::blank(colours.no_size()),
-            Self::DeviceIDs(ref ids)  => return ids.render(colours),
+            Self::Some(s) => s,
+            Self::None => return TextCell::blank(colours.no_size()),
+            Self::DeviceIDs(ref ids) => return ids.render(colours),
         };
         };
 
 
+        #[rustfmt::skip]
         let result = match size_format {
         let result = match size_format {
             SizeFormat::DecimalBytes  => NumberPrefix::decimal(size as f64),
             SizeFormat::DecimalBytes  => NumberPrefix::decimal(size as f64),
             SizeFormat::BinaryBytes   => NumberPrefix::binary(size as f64),
             SizeFormat::BinaryBytes   => NumberPrefix::binary(size as f64),
@@ -35,6 +40,7 @@ impl f::Size {
             }
             }
         };
         };
 
 
+        #[rustfmt::skip]
         let (prefix, n) = match result {
         let (prefix, n) = match result {
             NumberPrefix::Standalone(b)   => return TextCell::paint(colours.size(None), numerics.format_int(b)),
             NumberPrefix::Standalone(b)   => return TextCell::paint(colours.size(None), numerics.format_int(b)),
             NumberPrefix::Prefixed(p, n)  => (p, n),
             NumberPrefix::Prefixed(p, n)  => (p, n),
@@ -53,12 +59,12 @@ impl f::Size {
             contents: vec![
             contents: vec![
                 colours.size(Some(prefix)).paint(number),
                 colours.size(Some(prefix)).paint(number),
                 colours.unit(Some(prefix)).paint(symbol),
                 colours.unit(Some(prefix)).paint(symbol),
-            ].into(),
+            ]
+            .into(),
         }
         }
     }
     }
 }
 }
 
 
-
 impl f::DeviceIDs {
 impl f::DeviceIDs {
     fn render<C: Colours>(self, colours: &C) -> TextCell {
     fn render<C: Colours>(self, colours: &C) -> TextCell {
         let major = self.major.to_string();
         let major = self.major.to_string();
@@ -70,12 +76,12 @@ impl f::DeviceIDs {
                 colours.major().paint(major),
                 colours.major().paint(major),
                 colours.comma().paint(","),
                 colours.comma().paint(","),
                 colours.minor().paint(minor),
                 colours.minor().paint(minor),
-            ].into(),
+            ]
+            .into(),
         }
         }
     }
     }
 }
 }
 
 
-
 pub trait Colours {
 pub trait Colours {
     fn size(&self, prefix: Option<Prefix>) -> Style;
     fn size(&self, prefix: Option<Prefix>) -> Style;
     fn unit(&self, prefix: Option<Prefix>) -> Style;
     fn unit(&self, prefix: Option<Prefix>) -> Style;
@@ -86,97 +92,122 @@ pub trait Colours {
     fn minor(&self) -> Style;
     fn minor(&self) -> Style;
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 pub mod test {
 pub mod test {
     use super::Colours;
     use super::Colours;
-    use crate::output::cell::{TextCell, DisplayWidth};
-    use crate::output::table::SizeFormat;
     use crate::fs::fields as f;
     use crate::fs::fields as f;
+    use crate::output::cell::{DisplayWidth, TextCell};
+    use crate::output::table::SizeFormat;
 
 
-    use locale::Numeric as NumericLocale;
     use ansiterm::Colour::*;
     use ansiterm::Colour::*;
     use ansiterm::Style;
     use ansiterm::Style;
+    use locale::Numeric as NumericLocale;
     use number_prefix::Prefix;
     use number_prefix::Prefix;
 
 
-
     struct TestColours;
     struct TestColours;
 
 
+    #[rustfmt::skip]
     impl Colours for TestColours {
     impl Colours for TestColours {
         fn size(&self, _prefix: Option<Prefix>) -> Style { Fixed(66).normal() }
         fn size(&self, _prefix: Option<Prefix>) -> Style { Fixed(66).normal() }
         fn unit(&self, _prefix: Option<Prefix>) -> Style { Fixed(77).bold() }
         fn unit(&self, _prefix: Option<Prefix>) -> Style { Fixed(77).bold() }
-        fn no_size(&self)          -> Style { Black.italic() }
+        fn no_size(&self)                       -> Style { Black.italic() }
 
 
         fn major(&self) -> Style { Blue.on(Red) }
         fn major(&self) -> Style { Blue.on(Red) }
         fn comma(&self) -> Style { Green.italic() }
         fn comma(&self) -> Style { Green.italic() }
         fn minor(&self) -> Style { Cyan.on(Yellow) }
         fn minor(&self) -> Style { Cyan.on(Yellow) }
     }
     }
 
 
-
     #[test]
     #[test]
     fn directory() {
     fn directory() {
         let directory = f::Size::None;
         let directory = f::Size::None;
         let expected = TextCell::blank(Black.italic());
         let expected = TextCell::blank(Black.italic());
-        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
+        assert_eq!(
+            expected,
+            directory.render(
+                &TestColours,
+                SizeFormat::JustBytes,
+                &NumericLocale::english()
+            )
+        )
     }
     }
 
 
-
     #[test]
     #[test]
     fn file_decimal() {
     fn file_decimal() {
         let directory = f::Size::Some(2_100_000);
         let directory = f::Size::Some(2_100_000);
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(4),
             width: DisplayWidth::from(4),
-            contents: vec![
-                Fixed(66).paint("2.1"),
-                Fixed(77).bold().paint("M"),
-            ].into(),
+            contents: vec![Fixed(66).paint("2.1"), Fixed(77).bold().paint("M")].into(),
         };
         };
 
 
-        assert_eq!(expected, directory.render(&TestColours, SizeFormat::DecimalBytes, &NumericLocale::english()))
+        assert_eq!(
+            expected,
+            directory.render(
+                &TestColours,
+                SizeFormat::DecimalBytes,
+                &NumericLocale::english()
+            )
+        )
     }
     }
 
 
-
     #[test]
     #[test]
     fn file_binary() {
     fn file_binary() {
         let directory = f::Size::Some(1_048_576);
         let directory = f::Size::Some(1_048_576);
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(5),
             width: DisplayWidth::from(5),
-            contents: vec![
-                Fixed(66).paint("1.0"),
-                Fixed(77).bold().paint("Mi"),
-            ].into(),
+            contents: vec![Fixed(66).paint("1.0"), Fixed(77).bold().paint("Mi")].into(),
         };
         };
 
 
-        assert_eq!(expected, directory.render(&TestColours, SizeFormat::BinaryBytes, &NumericLocale::english()))
+        assert_eq!(
+            expected,
+            directory.render(
+                &TestColours,
+                SizeFormat::BinaryBytes,
+                &NumericLocale::english()
+            )
+        )
     }
     }
 
 
-
     #[test]
     #[test]
     fn file_bytes() {
     fn file_bytes() {
         let directory = f::Size::Some(1_048_576);
         let directory = f::Size::Some(1_048_576);
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(9),
             width: DisplayWidth::from(9),
-            contents: vec![
-                Fixed(66).paint("1,048,576"),
-            ].into(),
+            contents: vec![Fixed(66).paint("1,048,576")].into(),
         };
         };
 
 
-        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
+        assert_eq!(
+            expected,
+            directory.render(
+                &TestColours,
+                SizeFormat::JustBytes,
+                &NumericLocale::english()
+            )
+        )
     }
     }
 
 
-
     #[test]
     #[test]
     fn device_ids() {
     fn device_ids() {
-        let directory = f::Size::DeviceIDs(f::DeviceIDs { major: 10, minor: 80 });
+        let directory = f::Size::DeviceIDs(f::DeviceIDs {
+            major: 10,
+            minor: 80,
+        });
         let expected = TextCell {
         let expected = TextCell {
             width: DisplayWidth::from(5),
             width: DisplayWidth::from(5),
             contents: vec![
             contents: vec![
                 Blue.on(Red).paint("10"),
                 Blue.on(Red).paint("10"),
                 Green.italic().paint(","),
                 Green.italic().paint(","),
                 Cyan.on(Yellow).paint("80"),
                 Cyan.on(Yellow).paint("80"),
-            ].into(),
+            ]
+            .into(),
         };
         };
 
 
-        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
+        assert_eq!(
+            expected,
+            directory.render(
+                &TestColours,
+                SizeFormat::JustBytes,
+                &NumericLocale::english()
+            )
+        )
     }
     }
 }
 }

+ 4 - 2
src/output/render/times.rs

@@ -4,7 +4,6 @@ use crate::output::time::TimeFormat;
 use ansiterm::Style;
 use ansiterm::Style;
 use chrono::prelude::*;
 use chrono::prelude::*;
 
 
-
 pub trait Render {
 pub trait Render {
     fn render(self, style: Style, time_offset: FixedOffset, time_format: TimeFormat) -> TextCell;
     fn render(self, style: Style, time_offset: FixedOffset, time_format: TimeFormat) -> TextCell;
 }
 }
@@ -12,7 +11,10 @@ pub trait Render {
 impl Render for Option<NaiveDateTime> {
 impl Render for Option<NaiveDateTime> {
     fn render(self, style: Style, time_offset: FixedOffset, time_format: TimeFormat) -> TextCell {
     fn render(self, style: Style, time_offset: FixedOffset, time_format: TimeFormat) -> TextCell {
         let datestamp = if let Some(time) = self {
         let datestamp = if let Some(time) = self {
-            time_format.format(&DateTime::<FixedOffset>::from_naive_utc_and_offset(time, time_offset))
+            time_format.format(&DateTime::<FixedOffset>::from_naive_utc_and_offset(
+                time,
+                time_offset,
+            ))
         } else {
         } else {
             String::from("-")
             String::from("-")
         };
         };

+ 34 - 11
src/output/render/users.rs

@@ -11,30 +11,33 @@ pub trait Render {
 
 
 impl Render for Option<f::User> {
 impl Render for Option<f::User> {
     fn render<C: Colours, U: Users>(self, colours: &C, users: &U, format: UserFormat) -> TextCell {
     fn render<C: Colours, U: Users>(self, colours: &C, users: &U, format: UserFormat) -> TextCell {
+        #[rustfmt::skip]
         let uid = match self {
         let uid = match self {
             Some(u) => u.0,
             Some(u) => u.0,
             None    => return TextCell::blank(colours.no_user()),
             None    => return TextCell::blank(colours.no_user()),
         };
         };
+        #[rustfmt::skip]
         let user_name = match (format, users.get_user_by_uid(uid)) {
         let user_name = match (format, users.get_user_by_uid(uid)) {
             (_, None)                      => uid.to_string(),
             (_, None)                      => uid.to_string(),
             (UserFormat::Numeric, _)       => uid.to_string(),
             (UserFormat::Numeric, _)       => uid.to_string(),
             (UserFormat::Name, Some(user)) => user.name().to_string_lossy().into(),
             (UserFormat::Name, Some(user)) => user.name().to_string_lossy().into(),
         };
         };
 
 
-        let style = if users.get_current_uid() == uid { colours.you() }
-                                                    else { colours.someone_else() };
+        let style = if users.get_current_uid() == uid {
+            colours.you()
+        } else {
+            colours.someone_else()
+        };
         TextCell::paint(style, user_name)
         TextCell::paint(style, user_name)
     }
     }
 }
 }
 
 
-
 pub trait Colours {
 pub trait Colours {
     fn you(&self) -> Style;
     fn you(&self) -> Style;
     fn someone_else(&self) -> Style;
     fn someone_else(&self) -> Style;
     fn no_user(&self) -> Style;
     fn no_user(&self) -> Style;
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 #[allow(unused_results)]
 #[allow(unused_results)]
 pub mod test {
 pub mod test {
@@ -43,21 +46,20 @@ pub mod test {
     use crate::output::cell::TextCell;
     use crate::output::cell::TextCell;
     use crate::output::table::UserFormat;
     use crate::output::table::UserFormat;
 
 
-    use uzers::User;
-    use uzers::mock::MockUsers;
     use ansiterm::Colour::*;
     use ansiterm::Colour::*;
     use ansiterm::Style;
     use ansiterm::Style;
-
+    use uzers::mock::MockUsers;
+    use uzers::User;
 
 
     struct TestColours;
     struct TestColours;
 
 
+    #[rustfmt::skip]
     impl Colours for TestColours {
     impl Colours for TestColours {
         fn you(&self)          -> Style { Red.bold() }
         fn you(&self)          -> Style { Red.bold() }
         fn someone_else(&self) -> Style { Blue.underline() }
         fn someone_else(&self) -> Style { Blue.underline() }
         fn no_user(&self)      -> Style { Black.italic() }
         fn no_user(&self)      -> Style { Black.italic() }
     }
     }
 
 
-
     #[test]
     #[test]
     fn named() {
     fn named() {
         let mut users = MockUsers::with_current_uid(1000);
         let mut users = MockUsers::with_current_uid(1000);
@@ -65,9 +67,11 @@ pub mod test {
 
 
         let user = Some(f::User(1000));
         let user = Some(f::User(1000));
         let expected = TextCell::paint_str(Red.bold(), "enoch");
         let expected = TextCell::paint_str(Red.bold(), "enoch");
+        #[rustfmt::skip]
         assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Name));
         assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Name));
 
 
         let expected = TextCell::paint_str(Red.bold(), "1000");
         let expected = TextCell::paint_str(Red.bold(), "1000");
+        #[rustfmt::skip]
         assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Numeric));
         assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Numeric));
     }
     }
 
 
@@ -77,7 +81,9 @@ pub mod test {
 
 
         let user = Some(f::User(1000));
         let user = Some(f::User(1000));
         let expected = TextCell::paint_str(Red.bold(), "1000");
         let expected = TextCell::paint_str(Red.bold(), "1000");
+        #[rustfmt::skip]
         assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Name));
         assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Name));
+        #[rustfmt::skip]
         assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Numeric));
         assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Numeric));
     }
     }
 
 
@@ -88,20 +94,37 @@ pub mod test {
 
 
         let user = Some(f::User(1000));
         let user = Some(f::User(1000));
         let expected = TextCell::paint_str(Blue.underline(), "enoch");
         let expected = TextCell::paint_str(Blue.underline(), "enoch");
-        assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Name));
+        assert_eq!(
+            expected,
+            user.render(&TestColours, &users, UserFormat::Name)
+        );
     }
     }
 
 
     #[test]
     #[test]
     fn different_unnamed() {
     fn different_unnamed() {
         let user = Some(f::User(1000));
         let user = Some(f::User(1000));
         let expected = TextCell::paint_str(Blue.underline(), "1000");
         let expected = TextCell::paint_str(Blue.underline(), "1000");
-        assert_eq!(expected, user.render(&TestColours, &MockUsers::with_current_uid(0), UserFormat::Numeric));
+        assert_eq!(
+            expected,
+            user.render(
+                &TestColours,
+                &MockUsers::with_current_uid(0),
+                UserFormat::Numeric
+            )
+        );
     }
     }
 
 
     #[test]
     #[test]
     fn overflow() {
     fn overflow() {
         let user = Some(f::User(2_147_483_648));
         let user = Some(f::User(2_147_483_648));
         let expected = TextCell::paint_str(Blue.underline(), "2147483648");
         let expected = TextCell::paint_str(Blue.underline(), "2147483648");
-        assert_eq!(expected, user.render(&TestColours, &MockUsers::with_current_uid(0), UserFormat::Numeric));
+        assert_eq!(
+            expected,
+            user.render(
+                &TestColours,
+                &MockUsers::with_current_uid(0),
+                UserFormat::Numeric
+            )
+        );
     }
     }
 }
 }

+ 88 - 109
src/output/table.rs

@@ -10,22 +10,15 @@ use log::*;
 #[cfg(unix)]
 #[cfg(unix)]
 use uzers::UsersCache;
 use uzers::UsersCache;
 
 
-use crate::fs::{File, fields as f};
 use crate::fs::feature::git::GitCache;
 use crate::fs::feature::git::GitCache;
+use crate::fs::{fields as f, File};
 use crate::output::cell::TextCell;
 use crate::output::cell::TextCell;
-use crate::output::render::{PermissionsPlusRender, TimeRender};
 #[cfg(unix)]
 #[cfg(unix)]
-use crate::output::render::{
-    GroupRender,
-    OctalPermissionsRender,
-    UserRender
-};
+use crate::output::render::{GroupRender, OctalPermissionsRender, UserRender};
+use crate::output::render::{PermissionsPlusRender, TimeRender};
 use crate::output::time::TimeFormat;
 use crate::output::time::TimeFormat;
 use crate::theme::Theme;
 use crate::theme::Theme;
 
 
-
-
-
 /// Options for displaying a table.
 /// Options for displaying a table.
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub struct Options {
 pub struct Options {
@@ -39,7 +32,6 @@ pub struct Options {
 #[allow(clippy::struct_excessive_bools)]
 #[allow(clippy::struct_excessive_bools)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub struct Columns {
 pub struct Columns {
-
     /// At least one of these timestamps will be shown.
     /// At least one of these timestamps will be shown.
     pub time_types: TimeTypes,
     pub time_types: TimeTypes,
 
 
@@ -139,7 +131,6 @@ impl Columns {
     }
     }
 }
 }
 
 
-
 /// A table contains these.
 /// A table contains these.
 #[derive(Debug, Copy, Clone)]
 #[derive(Debug, Copy, Clone)]
 pub enum Column {
 pub enum Column {
@@ -173,28 +164,23 @@ pub enum Alignment {
 }
 }
 
 
 impl Column {
 impl Column {
-
     /// Get the alignment this column should use.
     /// Get the alignment this column should use.
     #[cfg(unix)]
     #[cfg(unix)]
     pub fn alignment(self) -> Alignment {
     pub fn alignment(self) -> Alignment {
         #[allow(clippy::wildcard_in_or_patterns)]
         #[allow(clippy::wildcard_in_or_patterns)]
         match self {
         match self {
-            Self::FileSize   |
-            Self::HardLinks  |
-            Self::Inode      |
-            Self::Blocksize  |
-            Self::GitStatus  => Alignment::Right,
-            Self::Timestamp(_) | 
-            _                => Alignment::Left,
+            Self::FileSize | Self::HardLinks | Self::Inode | Self::Blocksize | Self::GitStatus => {
+                Alignment::Right
+            }
+            Self::Timestamp(_) | _ => Alignment::Left,
         }
         }
     }
     }
 
 
     #[cfg(windows)]
     #[cfg(windows)]
     pub fn alignment(self) -> Alignment {
     pub fn alignment(self) -> Alignment {
         match self {
         match self {
-            Self::FileSize   |
-            Self::GitStatus  => Alignment::Right,
-            _                => Alignment::Left,
+            Self::FileSize | Self::GitStatus => Alignment::Right,
+            _ => Alignment::Left,
         }
         }
     }
     }
 
 
@@ -203,37 +189,35 @@ impl Column {
     pub fn header(self) -> &'static str {
     pub fn header(self) -> &'static str {
         match self {
         match self {
             #[cfg(unix)]
             #[cfg(unix)]
-            Self::Permissions   => "Permissions",
+            Self::Permissions => "Permissions",
             #[cfg(windows)]
             #[cfg(windows)]
-            Self::Permissions   => "Mode",
-            Self::FileSize      => "Size",
-            Self::Timestamp(t)  => t.header(),
+            Self::Permissions => "Mode",
+            Self::FileSize => "Size",
+            Self::Timestamp(t) => t.header(),
             #[cfg(unix)]
             #[cfg(unix)]
-            Self::Blocksize     => "Blocksize",
+            Self::Blocksize => "Blocksize",
             #[cfg(unix)]
             #[cfg(unix)]
-            Self::User          => "User",
+            Self::User => "User",
             #[cfg(unix)]
             #[cfg(unix)]
-            Self::Group         => "Group",
+            Self::Group => "Group",
             #[cfg(unix)]
             #[cfg(unix)]
-            Self::HardLinks     => "Links",
+            Self::HardLinks => "Links",
             #[cfg(unix)]
             #[cfg(unix)]
-            Self::Inode         => "inode",
-            Self::GitStatus     => "Git",
+            Self::Inode => "inode",
+            Self::GitStatus => "Git",
             Self::SubdirGitRepo(_) => "Repo",
             Self::SubdirGitRepo(_) => "Repo",
             #[cfg(unix)]
             #[cfg(unix)]
-            Self::Octal         => "Octal",
+            Self::Octal => "Octal",
             #[cfg(unix)]
             #[cfg(unix)]
             Self::SecurityContext => "Security Context",
             Self::SecurityContext => "Security Context",
         }
         }
     }
     }
 }
 }
 
 
-
 /// Formatting options for file sizes.
 /// Formatting options for file sizes.
 #[allow(clippy::enum_variant_names)]
 #[allow(clippy::enum_variant_names)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum SizeFormat {
 pub enum SizeFormat {
-
     /// Format the file size using **decimal** prefixes, such as “kilo”,
     /// Format the file size using **decimal** prefixes, such as “kilo”,
     /// “mega”, or “giga”.
     /// “mega”, or “giga”.
     DecimalBytes,
     DecimalBytes,
@@ -261,12 +245,10 @@ impl Default for SizeFormat {
     }
     }
 }
 }
 
 
-
 /// The types of a file’s time fields. These three fields are standard
 /// The types of a file’s time fields. These three fields are standard
 /// across most (all?) operating systems.
 /// across most (all?) operating systems.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum TimeType {
 pub enum TimeType {
-
     /// The file’s modified time (`st_mtime`).
     /// The file’s modified time (`st_mtime`).
     Modified,
     Modified,
 
 
@@ -281,25 +263,24 @@ pub enum TimeType {
 }
 }
 
 
 impl TimeType {
 impl TimeType {
-
     /// Returns the text to use for a column’s heading in the columns output.
     /// Returns the text to use for a column’s heading in the columns output.
     pub fn header(self) -> &'static str {
     pub fn header(self) -> &'static str {
         match self {
         match self {
-            Self::Modified  => "Date Modified",
-            Self::Changed   => "Date Changed",
-            Self::Accessed  => "Date Accessed",
-            Self::Created   => "Date Created",
+            Self::Modified => "Date Modified",
+            Self::Changed => "Date Changed",
+            Self::Accessed => "Date Accessed",
+            Self::Created => "Date Created",
         }
         }
     }
     }
 }
 }
 
 
-
 /// Fields for which of a file’s time fields should be displayed in the
 /// Fields for which of a file’s time fields should be displayed in the
 /// columns output.
 /// columns output.
 ///
 ///
 /// There should always be at least one of these — there’s no way to disable
 /// There should always be at least one of these — there’s no way to disable
 /// the time columns entirely (yet).
 /// the time columns entirely (yet).
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
+#[rustfmt::skip]
 #[allow(clippy::struct_excessive_bools)]
 #[allow(clippy::struct_excessive_bools)]
 pub struct TimeTypes {
 pub struct TimeTypes {
     pub modified: bool,
     pub modified: bool,
@@ -309,26 +290,23 @@ pub struct TimeTypes {
 }
 }
 
 
 impl Default for TimeTypes {
 impl Default for TimeTypes {
-
     /// By default, display just the ‘modified’ time. This is the most
     /// By default, display just the ‘modified’ time. This is the most
     /// common option, which is why it has this shorthand.
     /// common option, which is why it has this shorthand.
     fn default() -> Self {
     fn default() -> Self {
         Self {
         Self {
             modified: true,
             modified: true,
-            changed:  false,
+            changed: false,
             accessed: false,
             accessed: false,
-            created:  false,
+            created: false,
         }
         }
     }
     }
 }
 }
 
 
-
 /// The **environment** struct contains any data that could change between
 /// The **environment** struct contains any data that could change between
 /// running instances of exa, depending on the user’s computer’s configuration.
 /// 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.
 /// Any environment field should be able to be mocked up for test runs.
 pub struct Environment {
 pub struct Environment {
-
     /// The computer’s current time offset, determined from time zone.
     /// The computer’s current time offset, determined from time zone.
     time_offset: FixedOffset,
     time_offset: FixedOffset,
 
 
@@ -349,13 +327,18 @@ impl Environment {
     fn load_all() -> Self {
     fn load_all() -> Self {
         let time_offset = *Local::now().offset();
         let time_offset = *Local::now().offset();
 
 
-        let numeric = locale::Numeric::load_user_locale()
-                             .unwrap_or_else(|_| locale::Numeric::english());
+        let numeric =
+            locale::Numeric::load_user_locale().unwrap_or_else(|_| locale::Numeric::english());
 
 
         #[cfg(unix)]
         #[cfg(unix)]
         let users = Mutex::new(UsersCache::new());
         let users = Mutex::new(UsersCache::new());
 
 
-        Self { time_offset, numeric, #[cfg(unix)] users }
+        Self {
+            time_offset,
+            numeric,
+            #[cfg(unix)]
+            users,
+        }
     }
     }
 }
 }
 
 
@@ -363,7 +346,6 @@ lazy_static! {
     static ref ENVIRONMENT: Environment = Environment::load_all();
     static ref ENVIRONMENT: Environment = Environment::load_all();
 }
 }
 
 
-
 pub struct Table<'a> {
 pub struct Table<'a> {
     columns: Vec<Column>,
     columns: Vec<Column>,
     theme: &'a Theme,
     theme: &'a Theme,
@@ -405,17 +387,21 @@ impl<'a> Table<'a> {
     }
     }
 
 
     pub fn header_row(&self) -> Row {
     pub fn header_row(&self) -> Row {
-        let cells = self.columns.iter()
-                        .map(|c| TextCell::paint_str(self.theme.ui.header, c.header()))
-                        .collect();
+        let cells = self
+            .columns
+            .iter()
+            .map(|c| TextCell::paint_str(self.theme.ui.header, c.header()))
+            .collect();
 
 
         Row { cells }
         Row { cells }
     }
     }
 
 
     pub fn row_for_file(&self, file: &File<'_>, xattrs: bool) -> Row {
     pub fn row_for_file(&self, file: &File<'_>, xattrs: bool) -> Row {
-        let cells = self.columns.iter()
-                        .map(|c| self.display(file, *c, xattrs))
-                        .collect();
+        let cells = self
+            .columns
+            .iter()
+            .map(|c| self.display(file, *c, xattrs))
+            .collect();
 
 
         Row { cells }
         Row { cells }
     }
     }
@@ -429,7 +415,7 @@ impl<'a> Table<'a> {
         file.permissions().map(|p| f::PermissionsPlus {
         file.permissions().map(|p| f::PermissionsPlus {
             file_type: file.type_char(),
             file_type: file.type_char(),
             permissions: p,
             permissions: p,
-            xattrs
+            xattrs,
         })
         })
     }
     }
 
 
@@ -446,66 +432,62 @@ impl<'a> Table<'a> {
 
 
     #[cfg(unix)]
     #[cfg(unix)]
     fn octal_permissions(&self, file: &File<'_>) -> Option<f::OctalPermissions> {
     fn octal_permissions(&self, file: &File<'_>) -> Option<f::OctalPermissions> {
-        file.permissions().map(|p| f::OctalPermissions {
-            permissions: p,
-        })
+        file.permissions()
+            .map(|p| f::OctalPermissions { permissions: p })
     }
     }
 
 
     fn display(&self, file: &File<'_>, column: Column, xattrs: bool) -> TextCell {
     fn display(&self, file: &File<'_>, column: Column, xattrs: bool) -> TextCell {
         match column {
         match column {
-            Column::Permissions => {
-                self.permissions_plus(file, xattrs).render(self.theme)
-            }
-            Column::FileSize => {
-                file.size().render(self.theme, self.size_format, &self.env.numeric)
-            }
+            Column::Permissions => self.permissions_plus(file, xattrs).render(self.theme),
+            Column::FileSize => file
+                .size()
+                .render(self.theme, self.size_format, &self.env.numeric),
             #[cfg(unix)]
             #[cfg(unix)]
-            Column::HardLinks => {
-                file.links().render(self.theme, &self.env.numeric)
-            }
+            Column::HardLinks => file.links().render(self.theme, &self.env.numeric),
             #[cfg(unix)]
             #[cfg(unix)]
-            Column::Inode => {
-                file.inode().render(self.theme.ui.inode)
-            }
+            Column::Inode => file.inode().render(self.theme.ui.inode),
             #[cfg(unix)]
             #[cfg(unix)]
             Column::Blocksize => {
             Column::Blocksize => {
-                file.blocksize().render(self.theme, self.size_format, &self.env.numeric)
+                file.blocksize()
+                    .render(self.theme, self.size_format, &self.env.numeric)
             }
             }
             #[cfg(unix)]
             #[cfg(unix)]
             Column::User => {
             Column::User => {
-                file.user().render(self.theme, &*self.env.lock_users(), self.user_format)
+                file.user()
+                    .render(self.theme, &*self.env.lock_users(), self.user_format)
             }
             }
             #[cfg(unix)]
             #[cfg(unix)]
             Column::Group => {
             Column::Group => {
-                file.group().render(self.theme, &*self.env.lock_users(), self.user_format)
+                file.group()
+                    .render(self.theme, &*self.env.lock_users(), self.user_format)
             }
             }
             #[cfg(unix)]
             #[cfg(unix)]
-            Column::SecurityContext => {
-                file.security_context().render(self.theme)
-            }
-            Column::GitStatus => {
-                self.git_status(file).render(self.theme)
-            }
-            Column::SubdirGitRepo(status) => {
-                self.subdir_git_repo(file, status).render(self.theme)
-            }
+            Column::SecurityContext => file.security_context().render(self.theme),
+            Column::GitStatus => self.git_status(file).render(self.theme),
+            Column::SubdirGitRepo(status) => self.subdir_git_repo(file, status).render(self.theme),
             #[cfg(unix)]
             #[cfg(unix)]
-            Column::Octal => {
-                self.octal_permissions(file).render(self.theme.ui.octal)
-            }
-
-            Column::Timestamp(TimeType::Modified)  => {
-                file.modified_time().render(self.theme.ui.date, self.env.time_offset, self.time_format)
-            }
-            Column::Timestamp(TimeType::Changed)   => {
-                file.changed_time().render(self.theme.ui.date, self.env.time_offset, self.time_format)
-            }
-            Column::Timestamp(TimeType::Created)   => {
-                file.created_time().render(self.theme.ui.date, self.env.time_offset, self.time_format)
-            }
-            Column::Timestamp(TimeType::Accessed)  => {
-                file.accessed_time().render(self.theme.ui.date, self.env.time_offset, self.time_format)
-            }
+            Column::Octal => self.octal_permissions(file).render(self.theme.ui.octal),
+
+            Column::Timestamp(TimeType::Modified) => file.modified_time().render(
+                self.theme.ui.date,
+                self.env.time_offset,
+                self.time_format,
+            ),
+            Column::Timestamp(TimeType::Changed) => file.changed_time().render(
+                self.theme.ui.date,
+                self.env.time_offset,
+                self.time_format,
+            ),
+            Column::Timestamp(TimeType::Created) => file.created_time().render(
+                self.theme.ui.date,
+                self.env.time_offset,
+                self.time_format,
+            ),
+            Column::Timestamp(TimeType::Accessed) => file.accessed_time().render(
+                self.theme.ui.date,
+                self.env.time_offset,
+                self.time_format,
+            ),
         }
         }
     }
     }
 
 
@@ -517,10 +499,10 @@ impl<'a> Table<'a> {
             .unwrap_or_default()
             .unwrap_or_default()
     }
     }
 
 
-    fn subdir_git_repo(&self, file: &File<'_>, status : bool) -> f::SubdirGitRepo {
+    fn subdir_git_repo(&self, file: &File<'_>, status: bool) -> f::SubdirGitRepo {
         debug!("Getting subdir repo status for path {:?}", file.path);
         debug!("Getting subdir repo status for path {:?}", file.path);
 
 
-        if file.is_directory(){
+        if file.is_directory() {
             return f::SubdirGitRepo::from_path(&file.path, status);
             return f::SubdirGitRepo::from_path(&file.path, status);
         }
         }
         f::SubdirGitRepo::default()
         f::SubdirGitRepo::default()
@@ -529,9 +511,7 @@ impl<'a> Table<'a> {
     pub fn render(&self, row: Row) -> TextCell {
     pub fn render(&self, row: Row) -> TextCell {
         let mut cell = TextCell::default();
         let mut cell = TextCell::default();
 
 
-        let iter = row.cells.into_iter()
-                      .zip(self.widths.iter())
-                      .enumerate();
+        let iter = row.cells.into_iter().zip(self.widths.iter()).enumerate();
 
 
         for (n, (this_cell, width)) in iter {
         for (n, (this_cell, width)) in iter {
             let padding = width - *this_cell.width;
             let padding = width - *this_cell.width;
@@ -554,7 +534,6 @@ impl<'a> Table<'a> {
     }
     }
 }
 }
 
 
-
 pub struct TableWidths(Vec<usize>);
 pub struct TableWidths(Vec<usize>);
 
 
 impl Deref for TableWidths {
 impl Deref for TableWidths {

+ 30 - 29
src/output/time.rs

@@ -1,12 +1,11 @@
 //! Timestamp formatting.
 //! Timestamp formatting.
 
 
-use core::cmp::max;
-use std::time::Duration;
 use chrono::prelude::*;
 use chrono::prelude::*;
+use core::cmp::max;
 use lazy_static::lazy_static;
 use lazy_static::lazy_static;
+use std::time::Duration;
 use unicode_width::UnicodeWidthStr;
 use unicode_width::UnicodeWidthStr;
 
 
-
 /// Every timestamp in exa needs to be rendered by a **time format**.
 /// Every timestamp in exa needs to be rendered by a **time format**.
 /// Formatting times is tricky, because how a timestamp is rendered can
 /// Formatting times is tricky, because how a timestamp is rendered can
 /// depend on one or more of the following:
 /// depend on one or more of the following:
@@ -25,7 +24,6 @@ use unicode_width::UnicodeWidthStr;
 /// format string in an environment variable or something. Just these four.
 /// format string in an environment variable or something. Just these four.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum TimeFormat {
 pub enum TimeFormat {
-
     /// The **default format** uses the user’s locale to print month names,
     /// The **default format** uses the user’s locale to print month names,
     /// and specifies the timestamp down to the minute for recent times, and
     /// and specifies the timestamp down to the minute for recent times, and
     /// day for older times.
     /// day for older times.
@@ -51,13 +49,14 @@ pub enum TimeFormat {
 
 
 impl TimeFormat {
 impl TimeFormat {
     pub fn format(self, time: &DateTime<FixedOffset>) -> String {
     pub fn format(self, time: &DateTime<FixedOffset>) -> String {
-        match self {
+        #[rustfmt::skip]
+        return match self {
             Self::DefaultFormat  => default(time),
             Self::DefaultFormat  => default(time),
             Self::ISOFormat      => iso(time),
             Self::ISOFormat      => iso(time),
             Self::LongISO        => long(time),
             Self::LongISO        => long(time),
             Self::FullISO        => full(time),
             Self::FullISO        => full(time),
             Self::Relative       => relative(time),
             Self::Relative       => relative(time),
-        }
+        };
     }
     }
 }
 }
 
 
@@ -99,21 +98,19 @@ fn long(time: &DateTime<FixedOffset>) -> String {
 fn relative(time: &DateTime<FixedOffset>) -> String {
 fn relative(time: &DateTime<FixedOffset>) -> String {
     timeago::Formatter::new()
     timeago::Formatter::new()
         .ago("")
         .ago("")
-        .convert(
-            Duration::from_secs(
-                max(0, Local::now().timestamp() - time.timestamp())
-                // this .unwrap is safe since the call above can never result in a 
+        .convert(Duration::from_secs(
+            max(0, Local::now().timestamp() - time.timestamp())
+                // this .unwrap is safe since the call above can never result in a
                 // value < 0
                 // value < 0
-                .try_into().unwrap()
-            )
-        )
+                .try_into()
+                .unwrap(),
+        ))
 }
 }
 
 
 fn full(time: &DateTime<FixedOffset>) -> String {
 fn full(time: &DateTime<FixedOffset>) -> String {
     time.format("%Y-%m-%d %H:%M:%S.%f %z").to_string()
     time.format("%Y-%m-%d %H:%M:%S.%f %z").to_string()
 }
 }
 
 
-
 lazy_static! {
 lazy_static! {
 
 
     static ref CURRENT_YEAR: i32 = Local::now().year();
     static ref CURRENT_YEAR: i32 = Local::now().year();
@@ -147,25 +144,29 @@ mod test {
     #[test]
     #[test]
     fn short_month_width_hindi() {
     fn short_month_width_hindi() {
         let max_month_width = 4;
         let max_month_width = 4;
-        assert_eq!(true, [
-            "\u{091C}\u{0928}\u{0970}", // जन॰
-            "\u{092B}\u{093C}\u{0930}\u{0970}", // फ़र॰
-            "\u{092E}\u{093E}\u{0930}\u{094D}\u{091A}", // मार्च
-            "\u{0905}\u{092A}\u{094D}\u{0930}\u{0948}\u{0932}", // अप्रैल
-            "\u{092E}\u{0908}", // मई
-            "\u{091C}\u{0942}\u{0928}", // जून
-            "\u{091C}\u{0941}\u{0932}\u{0970}", // जुल॰
-            "\u{0905}\u{0917}\u{0970}", // अग॰
-            "\u{0938}\u{093F}\u{0924}\u{0970}", // सित॰
-            "\u{0905}\u{0915}\u{094D}\u{0924}\u{0942}\u{0970}", // अक्तू॰
-            "\u{0928}\u{0935}\u{0970}", // नव॰
-            "\u{0926}\u{093F}\u{0938}\u{0970}", // दिस॰
-        ].iter()
+        assert_eq!(
+            true,
+            [
+                "\u{091C}\u{0928}\u{0970}",                         // जन॰
+                "\u{092B}\u{093C}\u{0930}\u{0970}",                 // फ़र॰
+                "\u{092E}\u{093E}\u{0930}\u{094D}\u{091A}",         // मार्च
+                "\u{0905}\u{092A}\u{094D}\u{0930}\u{0948}\u{0932}", // अप्रैल
+                "\u{092E}\u{0908}",                                 // मई
+                "\u{091C}\u{0942}\u{0928}",                         // जून
+                "\u{091C}\u{0941}\u{0932}\u{0970}",                 // जुल॰
+                "\u{0905}\u{0917}\u{0970}",                         // अग॰
+                "\u{0938}\u{093F}\u{0924}\u{0970}",                 // सित॰
+                "\u{0905}\u{0915}\u{094D}\u{0924}\u{0942}\u{0970}", // अक्तू॰
+                "\u{0928}\u{0935}\u{0970}",                         // नव॰
+                "\u{0926}\u{093F}\u{0938}\u{0970}",                 // दिस॰
+            ]
+            .iter()
             .map(|month| format!(
             .map(|month| format!(
                 "{:<width$}",
                 "{:<width$}",
                 month,
                 month,
                 width = short_month_padding(max_month_width, month)
                 width = short_month_padding(max_month_width, month)
-            )).all(|string| UnicodeWidthStr::width(string.as_str()) == max_month_width)
+            ))
+            .all(|string| UnicodeWidthStr::width(string.as_str()) == max_month_width)
         );
         );
     }
     }
 }
 }

+ 27 - 21
src/output/tree.rs

@@ -38,10 +38,8 @@
 //! successfully `stat`ted, we don’t know how many files are going to exist in
 //! successfully `stat`ted, we don’t know how many files are going to exist in
 //! each directory)
 //! each directory)
 
 
-
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum TreePart {
 pub enum TreePart {
-
     /// Rightmost column, *not* the last in the directory.
     /// Rightmost column, *not* the last in the directory.
     Edge,
     Edge,
 
 
@@ -56,24 +54,22 @@ pub enum TreePart {
 }
 }
 
 
 impl TreePart {
 impl TreePart {
-
     /// Turn this tree part into ASCII-licious box drawing characters!
     /// Turn this tree part into ASCII-licious box drawing characters!
     /// (Warning: not actually ASCII)
     /// (Warning: not actually ASCII)
     pub fn ascii_art(self) -> &'static str {
     pub fn ascii_art(self) -> &'static str {
-        match self {
+        #[rustfmt::skip]
+        return match self {
             Self::Edge    => "├──",
             Self::Edge    => "├──",
             Self::Line    => "│  ",
             Self::Line    => "│  ",
             Self::Corner  => "└──",
             Self::Corner  => "└──",
             Self::Blank   => "   ",
             Self::Blank   => "   ",
-        }
+        };
     }
     }
 }
 }
 
 
-
 /// A **tree trunk** builds up arrays of tree parts over multiple depths.
 /// A **tree trunk** builds up arrays of tree parts over multiple depths.
 #[derive(Debug, Default)]
 #[derive(Debug, Default)]
 pub struct TreeTrunk {
 pub struct TreeTrunk {
-
     /// A stack tracks which tree characters should be printed. It’s
     /// A stack tracks which tree characters should be printed. It’s
     /// necessary to maintain information about the previously-printed
     /// necessary to maintain information about the previously-printed
     /// lines, as the output will change based on any previous entries.
     /// lines, as the output will change based on any previous entries.
@@ -85,7 +81,6 @@ pub struct TreeTrunk {
 
 
 #[derive(Debug, Copy, Clone)]
 #[derive(Debug, Copy, Clone)]
 pub struct TreeParams {
 pub struct TreeParams {
-
     /// How many directories deep into the tree structure this is. Directories
     /// How many directories deep into the tree structure this is. Directories
     /// on top have depth 0.
     /// on top have depth 0.
     depth: TreeDepth,
     depth: TreeDepth,
@@ -98,7 +93,6 @@ pub struct TreeParams {
 pub struct TreeDepth(pub usize);
 pub struct TreeDepth(pub usize);
 
 
 impl TreeTrunk {
 impl TreeTrunk {
-
     /// Calculates the tree parts for an entry at the given depth and
     /// Calculates the tree parts for an entry at the given depth and
     /// last-ness. The depth is used to determine where in the stack the tree
     /// last-ness. The depth is used to determine where in the stack the tree
     /// part should be inserted, and the last-ness is used to determine which
     /// part should be inserted, and the last-ness is used to determine which
@@ -107,19 +101,24 @@ impl TreeTrunk {
     /// This takes a `&mut self` because the results of each file are stored
     /// This takes a `&mut self` because the results of each file are stored
     /// and used in future rows.
     /// and used in future rows.
     pub fn new_row(&mut self, params: TreeParams) -> &[TreePart] {
     pub fn new_row(&mut self, params: TreeParams) -> &[TreePart] {
-
         // If this isn’t our first iteration, then update the tree parts thus
         // If this isn’t our first iteration, then update the tree parts thus
         // far to account for there being another row after it.
         // far to account for there being another row after it.
         if let Some(last) = self.last_params {
         if let Some(last) = self.last_params {
-            self.stack[last.depth.0] = if last.last { TreePart::Blank }
-                                               else { TreePart::Line };
+            self.stack[last.depth.0] = if last.last {
+                TreePart::Blank
+            } else {
+                TreePart::Line
+            };
         }
         }
 
 
         // Make sure the stack has enough space, then add or modify another
         // Make sure the stack has enough space, then add or modify another
         // part into it.
         // part into it.
         self.stack.resize(params.depth.0 + 1, TreePart::Edge);
         self.stack.resize(params.depth.0 + 1, TreePart::Edge);
-        self.stack[params.depth.0] = if params.last { TreePart::Corner }
-                                               else { TreePart::Edge };
+        self.stack[params.depth.0] = if params.last {
+            TreePart::Corner
+        } else {
+            TreePart::Edge
+        };
 
 
         self.last_params = Some(params);
         self.last_params = Some(params);
 
 
@@ -162,20 +161,24 @@ impl TreeDepth {
     /// Creates an iterator that, as well as yielding each value, yields a
     /// Creates an iterator that, as well as yielding each value, yields a
     /// `TreeParams` with the current depth and last flag filled in.
     /// `TreeParams` with the current depth and last flag filled in.
     pub fn iterate_over<I, T>(self, inner: I) -> Iter<I>
     pub fn iterate_over<I, T>(self, inner: I) -> Iter<I>
-    where I: ExactSizeIterator + Iterator<Item = T>
+    where
+        I: ExactSizeIterator + Iterator<Item = T>,
     {
     {
-        Iter { current_depth: self, inner }
+        Iter {
+            current_depth: self,
+            inner,
+        }
     }
     }
 }
 }
 
 
-
 pub struct Iter<I> {
 pub struct Iter<I> {
     current_depth: TreeDepth,
     current_depth: TreeDepth,
     inner: I,
     inner: I,
 }
 }
 
 
 impl<I, T> Iterator for Iter<I>
 impl<I, T> Iterator for Iter<I>
-where I: ExactSizeIterator + Iterator<Item = T>
+where
+    I: ExactSizeIterator + Iterator<Item = T>,
 {
 {
     type Item = (TreeParams, T);
     type Item = (TreeParams, T);
 
 
@@ -188,7 +191,6 @@ where I: ExactSizeIterator + Iterator<Item = T>
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod trunk_test {
 mod trunk_test {
     use super::*;
     use super::*;
@@ -197,12 +199,14 @@ mod trunk_test {
         TreeParams::new(TreeDepth(depth), last)
         TreeParams::new(TreeDepth(depth), last)
     }
     }
 
 
+    #[rustfmt::skip]
     #[test]
     #[test]
     fn empty_at_first() {
     fn empty_at_first() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
         assert_eq!(tt.new_row(params(0, true)),  &[ ]);
         assert_eq!(tt.new_row(params(0, true)),  &[ ]);
     }
     }
 
 
+    #[rustfmt::skip]
     #[test]
     #[test]
     fn one_child() {
     fn one_child() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
@@ -210,6 +214,7 @@ mod trunk_test {
         assert_eq!(tt.new_row(params(1, true)),  &[ TreePart::Corner ]);
         assert_eq!(tt.new_row(params(1, true)),  &[ TreePart::Corner ]);
     }
     }
 
 
+    #[rustfmt::skip]
     #[test]
     #[test]
     fn two_children() {
     fn two_children() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
@@ -218,6 +223,7 @@ mod trunk_test {
         assert_eq!(tt.new_row(params(1, true)),  &[ TreePart::Corner ]);
         assert_eq!(tt.new_row(params(1, true)),  &[ TreePart::Corner ]);
     }
     }
 
 
+    #[rustfmt::skip]
     #[test]
     #[test]
     fn two_times_two_children() {
     fn two_times_two_children() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
@@ -230,6 +236,7 @@ mod trunk_test {
         assert_eq!(tt.new_row(params(1, true)),  &[ TreePart::Corner ]);
         assert_eq!(tt.new_row(params(1, true)),  &[ TreePart::Corner ]);
     }
     }
 
 
+    #[rustfmt::skip]
     #[test]
     #[test]
     fn two_times_two_nested_children() {
     fn two_times_two_nested_children() {
         let mut tt = TreeTrunk::default();
         let mut tt = TreeTrunk::default();
@@ -245,14 +252,13 @@ mod trunk_test {
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod iter_test {
 mod iter_test {
     use super::*;
     use super::*;
 
 
     #[test]
     #[test]
     fn test_iteration() {
     fn test_iteration() {
-        let foos = &[ "first", "middle", "last" ];
+        let foos = &["first", "middle", "last"];
         let mut iter = TreeDepth::root().iterate_over(foos.iter());
         let mut iter = TreeDepth::root().iterate_over(foos.iter());
 
 
         let next = iter.next().unwrap();
         let next = iter.next().unwrap();

+ 36 - 31
src/theme/default_theme.rs

@@ -1,15 +1,15 @@
-use ansiterm::Style;
 use ansiterm::Colour::*;
 use ansiterm::Colour::*;
+use ansiterm::Style;
 
 
-use crate::theme::ColourScale;
 use crate::theme::ui_styles::*;
 use crate::theme::ui_styles::*;
-
+use crate::theme::ColourScale;
 
 
 impl UiStyles {
 impl UiStyles {
     pub fn default_theme(scale: ColourScale) -> Self {
     pub fn default_theme(scale: ColourScale) -> Self {
         Self {
         Self {
             colourful: true,
             colourful: true,
 
 
+            #[rustfmt::skip]
             filekinds: FileKinds {
             filekinds: FileKinds {
                 normal:       Style::default(),
                 normal:       Style::default(),
                 directory:    Blue.bold(),
                 directory:    Blue.bold(),
@@ -23,6 +23,7 @@ impl UiStyles {
                 mount_point:  Blue.bold().underline(),
                 mount_point:  Blue.bold().underline(),
             },
             },
 
 
+            #[rustfmt::skip]
             perms: Permissions {
             perms: Permissions {
                 user_read:           Yellow.bold(),
                 user_read:           Yellow.bold(),
                 user_write:          Red.bold(),
                 user_write:          Red.bold(),
@@ -45,6 +46,7 @@ impl UiStyles {
 
 
             size: Size::colourful(scale),
             size: Size::colourful(scale),
 
 
+            #[rustfmt::skip]
             users: Users {
             users: Users {
                 user_you:           Yellow.bold(),
                 user_you:           Yellow.bold(),
                 user_someone_else:  Style::default(),
                 user_someone_else:  Style::default(),
@@ -52,11 +54,13 @@ impl UiStyles {
                 group_not_yours:    Style::default(),
                 group_not_yours:    Style::default(),
             },
             },
 
 
+            #[rustfmt::skip]
             links: Links {
             links: Links {
                 normal:          Red.bold(),
                 normal:          Red.bold(),
                 multi_link_file: Red.on(Yellow),
                 multi_link_file: Red.on(Yellow),
             },
             },
 
 
+            #[rustfmt::skip]
             git: Git {
             git: Git {
                 new:         Green.normal(),
                 new:         Green.normal(),
                 modified:    Blue.normal(),
                 modified:    Blue.normal(),
@@ -75,7 +79,8 @@ impl UiStyles {
             },
             },
 
 
             security_context: SecurityContext {
             security_context: SecurityContext {
-                none:       Style::default(),
+                none: Style::default(),
+                #[rustfmt::skip]
                 selinux: SELinuxContext {
                 selinux: SELinuxContext {
                     colon: Style::default().dimmed(),
                     colon: Style::default().dimmed(),
                     user:  Blue.normal(),
                     user:  Blue.normal(),
@@ -85,47 +90,47 @@ impl UiStyles {
                 },
                 },
             },
             },
 
 
+            #[rustfmt::skip]
             file_type: FileType {
             file_type: FileType {
-                image: Purple.normal(),
-                video: Purple.bold(),
-                music: Cyan.normal(),
-                lossless: Cyan.bold(),
-                crypto: Green.bold(),
-                document: Green.normal(),
+                image:      Purple.normal(),
+                video:      Purple.bold(),
+                music:      Cyan.normal(),
+                lossless:   Cyan.bold(),
+                crypto:     Green.bold(),
+                document:   Green.normal(),
                 compressed: Red.normal(),
                 compressed: Red.normal(),
-                temp: White.normal(),
-                compiled: Yellow.normal(),
-                build: Yellow.bold().underline()
+                temp:       White.normal(),
+                compiled:   Yellow.normal(),
+                build:      Yellow.bold().underline(),
             },
             },
 
 
-            punctuation:  DarkGray.bold(),
-            date:         Blue.normal(),
-            inode:        Purple.normal(),
-            blocks:       Cyan.normal(),
-            octal:        Purple.normal(),
-            header:       Style::default().underline(),
-
-            symlink_path:         Cyan.normal(),
-            control_char:         Red.normal(),
-            broken_symlink:       Red.normal(),
-            broken_path_overlay:  Style::default().underline(),
+            punctuation: DarkGray.bold(),
+            date: Blue.normal(),
+            inode: Purple.normal(),
+            blocks: Cyan.normal(),
+            octal: Purple.normal(),
+            header: Style::default().underline(),
+
+            symlink_path: Cyan.normal(),
+            control_char: Red.normal(),
+            broken_symlink: Red.normal(),
+            broken_path_overlay: Style::default().underline(),
         }
         }
     }
     }
 }
 }
 
 
-
 impl Size {
 impl Size {
     pub fn colourful(scale: ColourScale) -> Self {
     pub fn colourful(scale: ColourScale) -> Self {
         match scale {
         match scale {
-            ColourScale::Gradient  => Self::colourful_gradient(),
-            ColourScale::Fixed     => Self::colourful_fixed(),
+            ColourScale::Gradient => Self::colourful_gradient(),
+            ColourScale::Fixed => Self::colourful_fixed(),
         }
         }
     }
     }
 
 
     fn colourful_fixed() -> Self {
     fn colourful_fixed() -> Self {
         Self {
         Self {
-            major:  Green.bold(),
-            minor:  Green.normal(),
+            major: Green.bold(),
+            minor: Green.normal(),
 
 
             number_byte: Green.bold(),
             number_byte: Green.bold(),
             number_kilo: Green.bold(),
             number_kilo: Green.bold(),
@@ -143,8 +148,8 @@ impl Size {
 
 
     fn colourful_gradient() -> Self {
     fn colourful_gradient() -> Self {
         Self {
         Self {
-            major:  Green.bold(),
-            minor:  Green.normal(),
+            major: Green.bold(),
+            minor: Green.normal(),
 
 
             number_byte: Green.normal(),
             number_byte: Green.normal(),
             number_kilo: Green.bold(),
             number_kilo: Green.bold(),

+ 37 - 24
src/theme/lsc.rs

@@ -1,9 +1,8 @@
 use std::iter::Peekable;
 use std::iter::Peekable;
 use std::ops::FnMut;
 use std::ops::FnMut;
 
 
-use ansiterm::{Colour, Style};
 use ansiterm::Colour::*;
 use ansiterm::Colour::*;
-
+use ansiterm::{Colour, Style};
 
 
 // Parsing the LS_COLORS environment variable into a map of names to Style values.
 // Parsing the LS_COLORS environment variable into a map of names to Style values.
 //
 //
@@ -26,23 +25,25 @@ pub struct LSColors<'var>(pub &'var str);
 
 
 impl<'var> LSColors<'var> {
 impl<'var> LSColors<'var> {
     pub fn each_pair<C>(&mut self, mut callback: C)
     pub fn each_pair<C>(&mut self, mut callback: C)
-    where C: FnMut(Pair<'var>)
+    where
+        C: FnMut(Pair<'var>),
     {
     {
         for next in self.0.split(':') {
         for next in self.0.split(':') {
-            let bits = next.split('=')
-                           .take(3)
-                           .collect::<Vec<_>>();
+            let bits = next.split('=').take(3).collect::<Vec<_>>();
 
 
-            if bits.len() == 2 && ! bits[0].is_empty() && ! bits[1].is_empty() {
-                callback(Pair { key: bits[0], value: bits[1] });
+            if bits.len() == 2 && !bits[0].is_empty() && !bits[1].is_empty() {
+                callback(Pair {
+                    key: bits[0],
+                    value: bits[1],
+                });
             }
             }
         }
         }
     }
     }
 }
 }
 
 
-
 fn parse_into_high_colour<'a, I>(iter: &mut Peekable<I>) -> Option<Colour>
 fn parse_into_high_colour<'a, I>(iter: &mut Peekable<I>) -> Option<Colour>
-where I: Iterator<Item = &'a str>
+where
+    I: Iterator<Item = &'a str>,
 {
 {
     match iter.peek() {
     match iter.peek() {
         Some(&"5") => {
         Some(&"5") => {
@@ -69,22 +70,22 @@ where I: Iterator<Item = &'a str>
                     }
                     }
                 }*/
                 }*/
 
 
-                if let (Some(r), Some(g), Some(b)) = (hexes.parse().ok(),
-                                                      iter.next().and_then(|s| s.parse().ok()),
-                                                      iter.next().and_then(|s| s.parse().ok()))
-                {
+                if let (Some(r), Some(g), Some(b)) = (
+                    hexes.parse().ok(),
+                    iter.next().and_then(|s| s.parse().ok()),
+                    iter.next().and_then(|s| s.parse().ok()),
+                ) {
                     return Some(RGB(r, g, b));
                     return Some(RGB(r, g, b));
                 }
                 }
             }
             }
         }
         }
 
 
-        _ => {},
+        _ => {}
     }
     }
 
 
     None
     None
 }
 }
 
 
-
 pub struct Pair<'var> {
 pub struct Pair<'var> {
     pub key: &'var str,
     pub key: &'var str,
     pub value: &'var str,
     pub value: &'var str,
@@ -97,7 +98,6 @@ impl<'var> Pair<'var> {
 
 
         while let Some(num) = iter.next() {
         while let Some(num) = iter.next() {
             match num.trim_start_matches('0') {
             match num.trim_start_matches('0') {
-
                 // Bold and italic
                 // Bold and italic
                 "1" => style = style.bold(),
                 "1" => style = style.bold(),
                 "2" => style = style.dimmed(),
                 "2" => style = style.dimmed(),
@@ -127,7 +127,11 @@ impl<'var> Pair<'var> {
                 "95" => style = style.fg(BrightPurple),
                 "95" => style = style.fg(BrightPurple),
                 "96" => style = style.fg(BrightCyan),
                 "96" => style = style.fg(BrightCyan),
                 "97" => style = style.fg(BrightGray),
                 "97" => style = style.fg(BrightGray),
-                "38" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.fg(c) },
+                "38" => {
+                    if let Some(c) = parse_into_high_colour(&mut iter) {
+                        style = style.fg(c);
+                    }
+                }
 
 
                 // Background colours
                 // Background colours
                 "40" => style = style.on(Black),
                 "40" => style = style.on(Black),
@@ -147,8 +151,12 @@ impl<'var> Pair<'var> {
                 "105" => style = style.on(BrightPurple),
                 "105" => style = style.on(BrightPurple),
                 "106" => style = style.on(BrightCyan),
                 "106" => style = style.on(BrightCyan),
                 "107" => style = style.on(BrightGray),
                 "107" => style = style.on(BrightGray),
-                "48" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.on(c) },
-                 _   => {/* ignore the error and do nothing */},
+                "48" => {
+                    if let Some(c) = parse_into_high_colour(&mut iter) {
+                        style = style.on(c);
+                    }
+                }
+                _ => { /* ignore the error and do nothing */ }
             }
             }
         }
         }
 
 
@@ -156,7 +164,6 @@ impl<'var> Pair<'var> {
     }
     }
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod ansi_test {
 mod ansi_test {
     use super::*;
     use super::*;
@@ -166,7 +173,14 @@ mod ansi_test {
         ($name:ident: $input:expr => $result:expr) => {
         ($name:ident: $input:expr => $result:expr) => {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                assert_eq!(Pair { key: "", value: $input }.to_style(), $result);
+                assert_eq!(
+                    Pair {
+                        key: "",
+                        value: $input
+                    }
+                    .to_style(),
+                    $result
+                );
             }
             }
         };
         };
     }
     }
@@ -207,7 +221,6 @@ mod ansi_test {
     test!(toohi: "48;5;999"           => Style::default());
     test!(toohi: "48;5;999"           => Style::default());
 }
 }
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 mod test {
 mod test {
     use super::*;
     use super::*;
@@ -217,7 +230,7 @@ mod test {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
                 let mut lscs = Vec::new();
                 let mut lscs = Vec::new();
-                LSColors($input).each_pair(|p| lscs.push( (p.key.clone(), p.to_style()) ));
+                LSColors($input).each_pair(|p| lscs.push((p.key.clone(), p.to_style())));
                 assert_eq!(lscs, $result.to_vec());
                 assert_eq!(lscs, $result.to_vec());
             }
             }
         };
         };

+ 67 - 48
src/theme/mod.rs

@@ -13,10 +13,8 @@ pub use self::lsc::LSColors;
 
 
 mod default_theme;
 mod default_theme;
 
 
-
 #[derive(PartialEq, Eq, Debug)]
 #[derive(PartialEq, Eq, Debug)]
 pub struct Options {
 pub struct Options {
-
     pub use_colours: UseColours,
     pub use_colours: UseColours,
 
 
     pub colour_scale: ColourScale,
     pub colour_scale: ColourScale,
@@ -33,7 +31,6 @@ pub struct Options {
 /// this check and only displays colours when they can be truly appreciated.
 /// this check and only displays colours when they can be truly appreciated.
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub enum UseColours {
 pub enum UseColours {
-
     /// Display them even when output isn’t going to a terminal.
     /// Display them even when output isn’t going to a terminal.
     Always,
     Always,
 
 
@@ -56,17 +53,17 @@ pub struct Definitions {
     pub exa: Option<String>,
     pub exa: Option<String>,
 }
 }
 
 
-
 pub struct Theme {
 pub struct Theme {
     pub ui: UiStyles,
     pub ui: UiStyles,
     pub exts: Box<dyn FileStyle>,
     pub exts: Box<dyn FileStyle>,
 }
 }
 
 
 impl Options {
 impl Options {
-
-    #[allow(trivial_casts)]   // the `as Box<_>` stuff below warns about this for some reason
+    #[allow(trivial_casts)] // the `as Box<_>` stuff below warns about this for some reason
     pub fn to_theme(&self, isatty: bool) -> Theme {
     pub fn to_theme(&self, isatty: bool) -> Theme {
-        if self.use_colours == UseColours::Never || (self.use_colours == UseColours::Automatic && ! isatty) {
+        if self.use_colours == UseColours::Never
+            || (self.use_colours == UseColours::Automatic && !isatty)
+        {
             let ui = UiStyles::plain();
             let ui = UiStyles::plain();
             let exts = Box::new(NoFileStyle);
             let exts = Box::new(NoFileStyle);
             return Theme { ui, exts };
             return Theme { ui, exts };
@@ -77,6 +74,7 @@ impl Options {
         let (exts, use_default_filetypes) = self.definitions.parse_color_vars(&mut ui);
         let (exts, use_default_filetypes) = self.definitions.parse_color_vars(&mut ui);
 
 
         // Use between 0 and 2 file name highlighters
         // Use between 0 and 2 file name highlighters
+        #[rustfmt::skip]
         let exts = match (exts.is_non_empty(), use_default_filetypes) {
         let exts = match (exts.is_non_empty(), use_default_filetypes) {
             (false, false)  => Box::new(NoFileStyle)     as Box<_>,
             (false, false)  => Box::new(NoFileStyle)     as Box<_>,
             (false,  true)  => Box::new(FileTypes)         as Box<_>,
             (false,  true)  => Box::new(FileTypes)         as Box<_>,
@@ -89,7 +87,6 @@ impl Options {
 }
 }
 
 
 impl Definitions {
 impl Definitions {
-
     /// Parse the environment variables into `LS_COLORS` pairs, putting file glob
     /// Parse the environment variables into `LS_COLORS` pairs, putting file glob
     /// colours into the `ExtensionMappings` that gets returned, and using the
     /// colours into the `ExtensionMappings` that gets returned, and using the
     /// two-character UI codes to modify the mutable `Colours`.
     /// two-character UI codes to modify the mutable `Colours`.
@@ -103,7 +100,7 @@ impl Definitions {
 
 
         if let Some(lsc) = &self.ls {
         if let Some(lsc) = &self.ls {
             LSColors(lsc).each_pair(|pair| {
             LSColors(lsc).each_pair(|pair| {
-                if ! colours.set_ls(&pair) {
+                if !colours.set_ls(&pair) {
                     match glob::Pattern::new(pair.key) {
                     match glob::Pattern::new(pair.key) {
                         Ok(pat) => {
                         Ok(pat) => {
                             exts.add(pat, pair.to_style());
                             exts.add(pat, pair.to_style());
@@ -125,7 +122,7 @@ impl Definitions {
             }
             }
 
 
             LSColors(exa).each_pair(|pair| {
             LSColors(exa).each_pair(|pair| {
-                if ! colours.set_ls(&pair) && ! colours.set_exa(&pair) {
+                if !colours.set_ls(&pair) && !colours.set_exa(&pair) {
                     match glob::Pattern::new(pair.key) {
                     match glob::Pattern::new(pair.key) {
                         Ok(pat) => {
                         Ok(pat) => {
                             exts.add(pat, pair.to_style());
                             exts.add(pat, pair.to_style());
@@ -142,7 +139,6 @@ impl Definitions {
     }
     }
 }
 }
 
 
-
 /// Determine the style to paint the text for the filename part of the output.
 /// Determine the style to paint the text for the filename part of the output.
 pub trait FileStyle: Sync {
 pub trait FileStyle: Sync {
     /// Return the style to paint the filename text for `file` from the given
     /// Return the style to paint the filename text for `file` from the given
@@ -164,16 +160,17 @@ impl FileStyle for NoFileStyle {
 // file type associations, while falling back to the default set if not set
 // file type associations, while falling back to the default set if not set
 // explicitly.
 // explicitly.
 impl<A, B> FileStyle for (A, B)
 impl<A, B> FileStyle for (A, B)
-where A: FileStyle,
-      B: FileStyle,
+where
+    A: FileStyle,
+    B: FileStyle,
 {
 {
     fn get_style(&self, file: &File<'_>, theme: &Theme) -> Option<Style> {
     fn get_style(&self, file: &File<'_>, theme: &Theme) -> Option<Style> {
-        self.0.get_style(file, theme)
+        self.0
+            .get_style(file, theme)
             .or_else(|| self.1.get_style(file, theme))
             .or_else(|| self.1.get_style(file, theme))
     }
     }
 }
 }
 
 
-
 #[derive(PartialEq, Debug, Default)]
 #[derive(PartialEq, Debug, Default)]
 struct ExtensionMappings {
 struct ExtensionMappings {
     mappings: Vec<(glob::Pattern, Style)>,
     mappings: Vec<(glob::Pattern, Style)>,
@@ -181,7 +178,7 @@ struct ExtensionMappings {
 
 
 impl ExtensionMappings {
 impl ExtensionMappings {
     fn is_non_empty(&self) -> bool {
     fn is_non_empty(&self) -> bool {
-        ! self.mappings.is_empty()
+        !self.mappings.is_empty()
     }
     }
 
 
     fn add(&mut self, pattern: glob::Pattern, style: Style) {
     fn add(&mut self, pattern: glob::Pattern, style: Style) {
@@ -194,9 +191,11 @@ impl ExtensionMappings {
 
 
 impl FileStyle for ExtensionMappings {
 impl FileStyle for ExtensionMappings {
     fn get_style(&self, file: &File<'_>, _theme: &Theme) -> Option<Style> {
     fn get_style(&self, file: &File<'_>, _theme: &Theme) -> Option<Style> {
-        self.mappings.iter().rev()
+        self.mappings
+            .iter()
+            .rev()
             .find(|t| t.0.matches(&file.name))
             .find(|t| t.0.matches(&file.name))
-            .map (|t| t.1)
+            .map(|t| t.1)
     }
     }
 }
 }
 
 
@@ -205,7 +204,8 @@ struct FileTypes;
 
 
 impl FileStyle for FileTypes {
 impl FileStyle for FileTypes {
     fn get_style(&self, file: &File<'_>, theme: &Theme) -> Option<Style> {
     fn get_style(&self, file: &File<'_>, theme: &Theme) -> Option<Style> {
-        match FileType::get_file_type(file) {
+        #[rustfmt::skip]
+        return match FileType::get_file_type(file) {
             Some(FileType::Image)      => Some(theme.ui.file_type.image),
             Some(FileType::Image)      => Some(theme.ui.file_type.image),
             Some(FileType::Video)      => Some(theme.ui.file_type.video),
             Some(FileType::Video)      => Some(theme.ui.file_type.video),
             Some(FileType::Music)      => Some(theme.ui.file_type.music),
             Some(FileType::Music)      => Some(theme.ui.file_type.music),
@@ -217,7 +217,7 @@ impl FileStyle for FileTypes {
             Some(FileType::Compiled)   => Some(theme.ui.file_type.compiled),
             Some(FileType::Compiled)   => Some(theme.ui.file_type.compiled),
             Some(FileType::Build)      => Some(theme.ui.file_type.build),
             Some(FileType::Build)      => Some(theme.ui.file_type.build),
             None                       => None
             None                       => None
-        }
+        };
     }
     }
 }
 }
 
 
@@ -226,30 +226,35 @@ impl render::BlocksColours for Theme {
     fn blocksize(&self, prefix: Option<number_prefix::Prefix>) -> Style {
     fn blocksize(&self, prefix: Option<number_prefix::Prefix>) -> Style {
         use number_prefix::Prefix::*;
         use number_prefix::Prefix::*;
 
 
-        match prefix {
+        #[rustfmt::skip]
+        return match prefix {
             Some(Kilo | Kibi) => self.ui.size.number_kilo,
             Some(Kilo | Kibi) => self.ui.size.number_kilo,
             Some(Mega | Mebi) => self.ui.size.number_mega,
             Some(Mega | Mebi) => self.ui.size.number_mega,
             Some(Giga | Gibi) => self.ui.size.number_giga,
             Some(Giga | Gibi) => self.ui.size.number_giga,
             Some(_)           => self.ui.size.number_huge,
             Some(_)           => self.ui.size.number_huge,
             None              => self.ui.size.number_byte,
             None              => self.ui.size.number_byte,
-        }
+        };
     }
     }
 
 
     fn unit(&self, prefix: Option<number_prefix::Prefix>) -> Style {
     fn unit(&self, prefix: Option<number_prefix::Prefix>) -> Style {
         use number_prefix::Prefix::*;
         use number_prefix::Prefix::*;
 
 
-        match prefix {
+        #[rustfmt::skip]
+        return match prefix {
             Some(Kilo | Kibi) => self.ui.size.unit_kilo,
             Some(Kilo | Kibi) => self.ui.size.unit_kilo,
             Some(Mega | Mebi) => self.ui.size.unit_mega,
             Some(Mega | Mebi) => self.ui.size.unit_mega,
             Some(Giga | Gibi) => self.ui.size.unit_giga,
             Some(Giga | Gibi) => self.ui.size.unit_giga,
             Some(_)           => self.ui.size.unit_huge,
             Some(_)           => self.ui.size.unit_huge,
             None              => self.ui.size.unit_byte,
             None              => self.ui.size.unit_byte,
-        }
+        };
     }
     }
 
 
-    fn no_blocksize(&self) -> Style { self.ui.punctuation }
+    fn no_blocksize(&self) -> Style {
+        self.ui.punctuation
+    }
 }
 }
 
 
+#[rustfmt::skip]
 impl render::FiletypeColours for Theme {
 impl render::FiletypeColours for Theme {
     fn normal(&self)       -> Style { self.ui.filekinds.normal }
     fn normal(&self)       -> Style { self.ui.filekinds.normal }
     fn directory(&self)    -> Style { self.ui.filekinds.directory }
     fn directory(&self)    -> Style { self.ui.filekinds.directory }
@@ -261,6 +266,7 @@ impl render::FiletypeColours for Theme {
     fn special(&self)      -> Style { self.ui.filekinds.special }
     fn special(&self)      -> Style { self.ui.filekinds.special }
 }
 }
 
 
+#[rustfmt::skip]
 impl render::GitColours for Theme {
 impl render::GitColours for Theme {
     fn not_modified(&self)  -> Style { self.ui.punctuation }
     fn not_modified(&self)  -> Style { self.ui.punctuation }
     #[allow(clippy::new_ret_no_self)]
     #[allow(clippy::new_ret_no_self)]
@@ -273,14 +279,16 @@ impl render::GitColours for Theme {
     fn conflicted(&self)    -> Style { self.ui.git.conflicted }
     fn conflicted(&self)    -> Style { self.ui.git.conflicted }
 }
 }
 
 
+#[rustfmt::skip]
 impl render::GitRepoColours for Theme {
 impl render::GitRepoColours for Theme {
-    fn branch_main(&self) -> Style { self.ui.git_repo.branch_main }
+    fn branch_main(&self)  -> Style { self.ui.git_repo.branch_main }
     fn branch_other(&self) -> Style { self.ui.git_repo.branch_other }
     fn branch_other(&self) -> Style { self.ui.git_repo.branch_other }
-    fn no_repo(&self) -> Style { self.ui.punctuation }
-    fn git_clean(&self) -> Style { self.ui.git_repo.git_clean }
-    fn git_dirty(&self) -> Style { self.ui.git_repo.git_dirty }
+    fn no_repo(&self)      -> Style { self.ui.punctuation }
+    fn git_clean(&self)    -> Style { self.ui.git_repo.git_clean }
+    fn git_dirty(&self)    -> Style { self.ui.git_repo.git_dirty }
 }
 }
 
 
+#[rustfmt::skip]
 #[cfg(unix)]
 #[cfg(unix)]
 impl render::GroupColours for Theme {
 impl render::GroupColours for Theme {
     fn yours(&self)      -> Style { self.ui.users.group_yours }
     fn yours(&self)      -> Style { self.ui.users.group_yours }
@@ -288,11 +296,13 @@ impl render::GroupColours for Theme {
     fn no_group(&self)   -> Style { self.ui.punctuation }
     fn no_group(&self)   -> Style { self.ui.punctuation }
 }
 }
 
 
+#[rustfmt::skip]
 impl render::LinksColours for Theme {
 impl render::LinksColours for Theme {
     fn normal(&self)           -> Style { self.ui.links.normal }
     fn normal(&self)           -> Style { self.ui.links.normal }
     fn multi_link_file(&self)  -> Style { self.ui.links.multi_link_file }
     fn multi_link_file(&self)  -> Style { self.ui.links.multi_link_file }
 }
 }
 
 
+#[rustfmt::skip]
 impl render::PermissionsColours for Theme {
 impl render::PermissionsColours for Theme {
     fn dash(&self)               -> Style { self.ui.punctuation }
     fn dash(&self)               -> Style { self.ui.punctuation }
     fn user_read(&self)          -> Style { self.ui.perms.user_read }
     fn user_read(&self)          -> Style { self.ui.perms.user_read }
@@ -314,33 +324,40 @@ impl render::SizeColours for Theme {
     fn size(&self, prefix: Option<number_prefix::Prefix>) -> Style {
     fn size(&self, prefix: Option<number_prefix::Prefix>) -> Style {
         use number_prefix::Prefix::*;
         use number_prefix::Prefix::*;
 
 
-        match prefix {
+        #[rustfmt::skip]
+        return match prefix {
             Some(Kilo | Kibi) => self.ui.size.number_kilo,
             Some(Kilo | Kibi) => self.ui.size.number_kilo,
             Some(Mega | Mebi) => self.ui.size.number_mega,
             Some(Mega | Mebi) => self.ui.size.number_mega,
             Some(Giga | Gibi) => self.ui.size.number_giga,
             Some(Giga | Gibi) => self.ui.size.number_giga,
             Some(_)           => self.ui.size.number_huge,
             Some(_)           => self.ui.size.number_huge,
             None              => self.ui.size.number_byte,
             None              => self.ui.size.number_byte,
-        }
+        };
     }
     }
 
 
     fn unit(&self, prefix: Option<number_prefix::Prefix>) -> Style {
     fn unit(&self, prefix: Option<number_prefix::Prefix>) -> Style {
         use number_prefix::Prefix::*;
         use number_prefix::Prefix::*;
 
 
-        match prefix {
+        #[rustfmt::skip]
+        return match prefix {
             Some(Kilo | Kibi) => self.ui.size.unit_kilo,
             Some(Kilo | Kibi) => self.ui.size.unit_kilo,
             Some(Mega | Mebi) => self.ui.size.unit_mega,
             Some(Mega | Mebi) => self.ui.size.unit_mega,
             Some(Giga | Gibi) => self.ui.size.unit_giga,
             Some(Giga | Gibi) => self.ui.size.unit_giga,
             Some(_)           => self.ui.size.unit_huge,
             Some(_)           => self.ui.size.unit_huge,
             None              => self.ui.size.unit_byte,
             None              => self.ui.size.unit_byte,
-        }
+        };
     }
     }
 
 
+    #[rustfmt::skip]
     fn no_size(&self) -> Style { self.ui.punctuation }
     fn no_size(&self) -> Style { self.ui.punctuation }
+    #[rustfmt::skip]
     fn major(&self)   -> Style { self.ui.size.major }
     fn major(&self)   -> Style { self.ui.size.major }
+    #[rustfmt::skip]
     fn comma(&self)   -> Style { self.ui.punctuation }
     fn comma(&self)   -> Style { self.ui.punctuation }
+    #[rustfmt::skip]
     fn minor(&self)   -> Style { self.ui.size.minor }
     fn minor(&self)   -> Style { self.ui.size.minor }
 }
 }
 
 
+#[rustfmt::skip]
 #[cfg(unix)]
 #[cfg(unix)]
 impl render::UserColours for Theme {
 impl render::UserColours for Theme {
     fn you(&self)           -> Style { self.ui.users.user_you }
     fn you(&self)           -> Style { self.ui.users.user_you }
@@ -348,6 +365,7 @@ impl render::UserColours for Theme {
     fn no_user(&self)       -> Style { self.ui.punctuation }
     fn no_user(&self)       -> Style { self.ui.punctuation }
 }
 }
 
 
+#[rustfmt::skip]
 impl FileNameColours for Theme {
 impl FileNameColours for Theme {
     fn symlink_path(&self)        -> Style { self.ui.symlink_path }
     fn symlink_path(&self)        -> Style { self.ui.symlink_path }
     fn normal_arrow(&self)        -> Style { self.ui.punctuation }
     fn normal_arrow(&self)        -> Style { self.ui.punctuation }
@@ -359,10 +377,13 @@ impl FileNameColours for Theme {
     fn mount_point(&self)         -> Style { self.ui.filekinds.mount_point }
     fn mount_point(&self)         -> Style { self.ui.filekinds.mount_point }
 
 
     fn colour_file(&self, file: &File<'_>) -> Style {
     fn colour_file(&self, file: &File<'_>) -> Style {
-        self.exts.get_style(file, self).unwrap_or(self.ui.filekinds.normal)
+        self.exts
+            .get_style(file, self)
+            .unwrap_or(self.ui.filekinds.normal)
     }
     }
 }
 }
 
 
+#[rustfmt::skip]
 impl render::SecurityCtxColours for Theme {
 impl render::SecurityCtxColours for Theme {
     fn none(&self)          -> Style { self.ui.security_context.none }
     fn none(&self)          -> Style { self.ui.security_context.none }
     fn selinux_colon(&self) -> Style { self.ui.security_context.selinux.colon }
     fn selinux_colon(&self) -> Style { self.ui.security_context.selinux.colon }
@@ -372,7 +393,6 @@ impl render::SecurityCtxColours for Theme {
     fn selinux_range(&self) -> Style { self.ui.security_context.selinux.range }
     fn selinux_range(&self) -> Style { self.ui.security_context.selinux.range }
 }
 }
 
 
-
 /// Some of the styles are **overlays**: although they have the same attribute
 /// Some of the styles are **overlays**: although they have the same attribute
 /// set as regular styles (foreground and background colours, bold, underline,
 /// set as regular styles (foreground and background colours, bold, underline,
 /// etc), they’re intended to be used to *amend* existing styles.
 /// etc), they’re intended to be used to *amend* existing styles.
@@ -385,6 +405,7 @@ impl render::SecurityCtxColours for Theme {
 /// character”, there are styles for “link path”, “control character”, and
 /// character”, there are styles for “link path”, “control character”, and
 /// “broken link overlay”, the latter of which is just set to override the
 /// “broken link overlay”, the latter of which is just set to override the
 /// underline attribute on the other two.
 /// underline attribute on the other two.
+#[rustfmt::skip]
 fn apply_overlay(mut base: Style, overlay: Style) -> Style {
 fn apply_overlay(mut base: Style, overlay: Style) -> Style {
     if let Some(fg) = overlay.foreground { base.foreground = Some(fg); }
     if let Some(fg) = overlay.foreground { base.foreground = Some(fg); }
     if let Some(bg) = overlay.background { base.background = Some(bg); }
     if let Some(bg) = overlay.background { base.background = Some(bg); }
@@ -402,7 +423,6 @@ fn apply_overlay(mut base: Style, overlay: Style) -> Style {
 }
 }
 // TODO: move this function to the ansiterm crate
 // TODO: move this function to the ansiterm crate
 
 
-
 #[cfg(test)]
 #[cfg(test)]
 #[cfg(unix)]
 #[cfg(unix)]
 mod customs_test {
 mod customs_test {
@@ -419,7 +439,7 @@ mod customs_test {
                 $process_expected();
                 $process_expected();
 
 
                 let definitions = Definitions {
                 let definitions = Definitions {
-                    ls:  Some($ls.into()),
+                    ls: Some($ls.into()),
                     exa: Some($exa.into()),
                     exa: Some($exa.into()),
                 };
                 };
 
 
@@ -431,13 +451,13 @@ mod customs_test {
         ($name:ident:  ls $ls:expr, exa $exa:expr  =>  exts $mappings:expr) => {
         ($name:ident:  ls $ls:expr, exa $exa:expr  =>  exts $mappings:expr) => {
             #[test]
             #[test]
             fn $name() {
             fn $name() {
-                let mappings: Vec<(glob::Pattern, Style)>
-                    = $mappings.iter()
-                               .map(|t| (glob::Pattern::new(t.0).unwrap(), t.1))
-                               .collect();
+                let mappings: Vec<(glob::Pattern, Style)> = $mappings
+                    .iter()
+                    .map(|t| (glob::Pattern::new(t.0).unwrap(), t.1))
+                    .collect();
 
 
                 let definitions = Definitions {
                 let definitions = Definitions {
-                    ls:  Some($ls.into()),
+                    ls: Some($ls.into()),
                     exa: Some($exa.into()),
                     exa: Some($exa.into()),
                 };
                 };
 
 
@@ -451,13 +471,13 @@ mod customs_test {
                 let mut $expected = UiStyles::default();
                 let mut $expected = UiStyles::default();
                 $process_expected();
                 $process_expected();
 
 
-                let mappings: Vec<(glob::Pattern, Style)>
-                    = $mappings.iter()
-                               .map(|t| (glob::Pattern::new(t.0).unwrap(), t.1))
-                               .collect();
+                let mappings: Vec<(glob::Pattern, Style)> = $mappings
+                    .iter()
+                    .map(|t| (glob::Pattern::new(t.0).unwrap(), t.1))
+                    .collect();
 
 
                 let definitions = Definitions {
                 let definitions = Definitions {
-                    ls:  Some($ls.into()),
+                    ls: Some($ls.into()),
                     exa: Some($exa.into()),
                     exa: Some($exa.into()),
                 };
                 };
 
 
@@ -469,7 +489,6 @@ mod customs_test {
         };
         };
     }
     }
 
 
-
     // LS_COLORS can affect all of these colours:
     // LS_COLORS can affect all of these colours:
     test!(ls_di:   ls "di=31", exa ""  =>  colours c -> { c.filekinds.directory    = Red.normal();    });
     test!(ls_di:   ls "di=31", exa ""  =>  colours c -> { c.filekinds.directory    = Red.normal();    });
     test!(ls_ex:   ls "ex=32", exa ""  =>  colours c -> { c.filekinds.executable   = Green.normal();  });
     test!(ls_ex:   ls "ex=32", exa ""  =>  colours c -> { c.filekinds.executable   = Green.normal();  });

+ 18 - 9
src/theme/ui_styles.rs

@@ -2,7 +2,7 @@ use ansiterm::Style;
 
 
 use crate::theme::lsc::Pair;
 use crate::theme::lsc::Pair;
 
 
-
+#[rustfmt::skip]
 #[derive(Debug, Default, PartialEq)]
 #[derive(Debug, Default, PartialEq)]
 pub struct UiStyles {
 pub struct UiStyles {
     pub colourful: bool,
     pub colourful: bool,
@@ -30,6 +30,7 @@ pub struct UiStyles {
     pub broken_path_overlay:  Style,  // bO
     pub broken_path_overlay:  Style,  // bO
 }
 }
 
 
+#[rustfmt::skip]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct FileKinds {
 pub struct FileKinds {
     pub normal: Style,        // fi
     pub normal: Style,        // fi
@@ -44,6 +45,7 @@ pub struct FileKinds {
     pub mount_point: Style,   // mp
     pub mount_point: Style,   // mp
 }
 }
 
 
+#[rustfmt::skip]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct Permissions {
 pub struct Permissions {
     pub user_read:          Style,  // ur
     pub user_read:          Style,  // ur
@@ -65,6 +67,7 @@ pub struct Permissions {
     pub attribute: Style,           // xa
     pub attribute: Style,           // xa
 }
 }
 
 
+#[rustfmt::skip]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct Size {
 pub struct Size {
     pub major: Style,        // df
     pub major: Style,        // df
@@ -83,6 +86,7 @@ pub struct Size {
     pub unit_huge: Style,    // sb ut
     pub unit_huge: Style,    // sb ut
 }
 }
 
 
+#[rustfmt::skip]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct Users {
 pub struct Users {
     pub user_you: Style,           // uu
     pub user_you: Style,           // uu
@@ -91,12 +95,14 @@ pub struct Users {
     pub group_not_yours: Style,    // gn
     pub group_not_yours: Style,    // gn
 }
 }
 
 
+#[rustfmt::skip]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct Links {
 pub struct Links {
     pub normal: Style,           // lc
     pub normal: Style,           // lc
     pub multi_link_file: Style,  // lm
     pub multi_link_file: Style,  // lm
 }
 }
 
 
+#[rustfmt::skip]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct Git {
 pub struct Git {
     pub new: Style,         // ga
     pub new: Style,         // ga
@@ -108,6 +114,7 @@ pub struct Git {
     pub conflicted: Style,  // gc
     pub conflicted: Style,  // gc
 }
 }
 
 
+#[rustfmt::skip]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct GitRepo {
 pub struct GitRepo {
     pub branch_main: Style,
     pub branch_main: Style,
@@ -119,12 +126,13 @@ pub struct GitRepo {
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct SELinuxContext {
 pub struct SELinuxContext {
     pub colon: Style,
     pub colon: Style,
-    pub user:  Style,  // Su
-    pub role:  Style,  // Sr
-    pub typ:   Style,  // St
-    pub range: Style,  // Sl
+    pub user: Style,  // Su
+    pub role: Style,  // Sr
+    pub typ: Style,   // St
+    pub range: Style, // Sl
 }
 }
 
 
+#[rustfmt::skip]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct SecurityContext {
 pub struct SecurityContext {
     pub none:    Style, // Sn
     pub none:    Style, // Sn
@@ -132,6 +140,7 @@ pub struct SecurityContext {
 }
 }
 
 
 /// Drawing styles based on the type of file (video, image, compressed, etc)
 /// Drawing styles based on the type of file (video, image, compressed, etc)
+#[rustfmt::skip]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct FileType {
 pub struct FileType {
     pub image: Style,       // im - image file
     pub image: Style,       // im - image file
@@ -152,13 +161,12 @@ impl UiStyles {
     }
     }
 }
 }
 
 
-
 impl UiStyles {
 impl UiStyles {
-
     /// Sets a value on this set of colours using one of the keys understood
     /// Sets a value on this set of colours using one of the keys understood
     /// by the `LS_COLORS` environment variable. Invalid keys set nothing, but
     /// by the `LS_COLORS` environment variable. Invalid keys set nothing, but
     /// return false.
     /// return false.
     pub fn set_ls(&mut self, pair: &Pair<'_>) -> bool {
     pub fn set_ls(&mut self, pair: &Pair<'_>) -> bool {
+        #[rustfmt::skip]
         match pair.key {
         match pair.key {
             "di" => self.filekinds.directory    = pair.to_style(),  // DIR
             "di" => self.filekinds.directory    = pair.to_style(),  // DIR
             "ex" => self.filekinds.executable   = pair.to_style(),  // EXEC
             "ex" => self.filekinds.executable   = pair.to_style(),  // EXEC
@@ -173,7 +181,7 @@ impl UiStyles {
              // Codes we don’t do anything with:
              // Codes we don’t do anything with:
              // MULTIHARDLINK, DOOR, SETUID, SETGID, CAPABILITY,
              // MULTIHARDLINK, DOOR, SETUID, SETGID, CAPABILITY,
              // STICKY_OTHER_WRITABLE, OTHER_WRITABLE, STICKY, MISSING
              // STICKY_OTHER_WRITABLE, OTHER_WRITABLE, STICKY, MISSING
-        }
+        };
         true
         true
     }
     }
 
 
@@ -182,6 +190,7 @@ impl UiStyles {
     /// but return false. This doesn’t take the `LS_COLORS` keys into account,
     /// but return false. This doesn’t take the `LS_COLORS` keys into account,
     /// so `set_ls` should have been run first.
     /// so `set_ls` should have been run first.
     pub fn set_exa(&mut self, pair: &Pair<'_>) -> bool {
     pub fn set_exa(&mut self, pair: &Pair<'_>) -> bool {
+        #[rustfmt::skip]
         match pair.key {
         match pair.key {
             "ur" => self.perms.user_read                = pair.to_style(),
             "ur" => self.perms.user_read                = pair.to_style(),
             "uw" => self.perms.user_write               = pair.to_style(),
             "uw" => self.perms.user_write               = pair.to_style(),
@@ -259,7 +268,7 @@ impl UiStyles {
             "Sl" => self.security_context.selinux.range = pair.to_style(),
             "Sl" => self.security_context.selinux.range = pair.to_style(),
 
 
              _   => return false,
              _   => return false,
-        }
+        };
 
 
         true
         true
     }
     }

+ 5 - 9
tests/cli_tests.rs

@@ -1,26 +1,22 @@
 #[test]
 #[test]
 fn cli_all_tests() {
 fn cli_all_tests() {
-    trycmd::TestCases::new()
-        .case("tests/cmd/*_all.toml");
+    trycmd::TestCases::new().case("tests/cmd/*_all.toml");
 }
 }
 
 
 #[test]
 #[test]
 #[cfg(unix)]
 #[cfg(unix)]
 fn cli_unix_tests() {
 fn cli_unix_tests() {
-    trycmd::TestCases::new()
-        .case("tests/cmd/*_unix.toml");
+    trycmd::TestCases::new().case("tests/cmd/*_unix.toml");
 }
 }
 
 
 #[test]
 #[test]
 #[cfg(windows)]
 #[cfg(windows)]
 fn cli_windows_tests() {
 fn cli_windows_tests() {
-    trycmd::TestCases::new()
-        .case("tests/cmd/*_windows.toml");
+    trycmd::TestCases::new().case("tests/cmd/*_windows.toml");
 }
 }
 
 
 #[test]
 #[test]
-#[cfg(feature="nix")]
+#[cfg(feature = "nix")]
 fn cli_nix_tests() {
 fn cli_nix_tests() {
-    trycmd::TestCases::new()
-        .case("tests/cmd/*_nix.toml");
+    trycmd::TestCases::new().case("tests/cmd/*_nix.toml");
 }
 }

+ 1 - 0
treefmt.nix

@@ -10,5 +10,6 @@
   };
   };
   settings = {
   settings = {
     formatter.shellcheck.includes = ["*.sh" "./completions/bash/eza"];
     formatter.shellcheck.includes = ["*.sh" "./completions/bash/eza"];
+    formatter.rustfmt.excludes = ["src/options/flags.rs"];
   };
   };
 }
 }