From f8df02dae7f3cc4121c9bff2c33a584e449ceaa0 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Sat, 10 Oct 2020 19:49:46 +0100 Subject: [PATCH] Batch source formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I read through every file and applied a couple of rustfmt suggestions. The brace placement and alignment of items on similar lines has been made consistent, even if neither are rustfmt's default style (a file has been put in place to enforce this). Other changes are: • Alphabetical imports and modules • Comma placement at the end of match blocks • Use newlines and indentation judiciously • Spaces around associated types • Spaces after negations (it makes it more clear imho) • Comment formatting • Use early-returns and Optional `?` where appropriate --- .rustfmt.toml | 1 + build.rs | 6 +- src/fs/dir.rs | 30 ++++---- src/fs/feature/git.rs | 53 ++++++++----- src/fs/feature/mod.rs | 11 ++- src/fs/feature/xattr.rs | 125 +++++++++++++++++++----------- src/fs/fields.rs | 21 +++-- src/fs/file.rs | 61 ++++++++------- src/fs/filter.rs | 42 +++++----- src/fs/mod.rs | 2 +- src/info/filetype.rs | 18 +++-- src/info/sources.rs | 4 +- src/logger.rs | 10 +-- src/main.rs | 115 +++++++++++++++------------- src/options/dir_action.rs | 2 +- src/options/filter.rs | 99 ++++++++++++++++-------- src/options/flags.rs | 6 +- src/options/help.rs | 5 +- src/options/misfire.rs | 30 ++++---- src/options/mod.rs | 14 ++-- src/options/parser.rs | 28 ++++--- src/options/style.rs | 61 ++++++++------- src/options/vars.rs | 2 +- src/options/view.rs | 37 ++++----- src/output/cell.rs | 8 +- src/output/details.rs | 72 ++++++++++-------- src/output/escape.rs | 29 +++---- src/output/file_name.rs | 80 ++++++++++++------- src/output/grid.rs | 20 ++--- src/output/grid_details.rs | 79 ++++++++++--------- src/output/icons.rs | 48 ++++++++---- src/output/lines.rs | 12 +-- src/output/mod.rs | 2 +- src/output/render/blocks.rs | 2 +- src/output/render/filetype.rs | 16 ++-- src/output/render/git.rs | 2 +- src/output/render/groups.rs | 8 +- src/output/render/inode.rs | 2 +- src/output/render/links.rs | 2 +- src/output/render/octal.rs | 14 ++-- src/output/render/permissions.rs | 16 ++-- src/output/render/size.rs | 14 ++-- src/output/render/times.rs | 19 +++-- src/output/render/users.rs | 5 +- src/output/table.rs | 127 +++++++++++++++++++++---------- src/output/time.rs | 29 +++---- src/output/tree.rs | 39 +++++----- src/style/colours.rs | 14 ++-- src/style/lsc.rs | 26 ++++--- 49 files changed, 861 insertions(+), 607 deletions(-) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..c7ad93b --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +disable_all_formatting = true diff --git a/build.rs b/build.rs index 083126e..239d762 100644 --- a/build.rs +++ b/build.rs @@ -11,8 +11,9 @@ /// - https://crates.io/crates/vergen extern crate datetime; -use std::io::Result as IOResult; use std::env; +use std::io::Result as IOResult; + fn git_hash() -> String { use std::process::Command; @@ -52,7 +53,8 @@ fn write_statics() -> IOResult<()> { let ver = if is_development_version() { format!("exa v{} ({} built on {})", cargo_version(), git_hash(), build_date()) - } else { + } + else { format!("exa v{}", cargo_version()) }; diff --git a/src/fs/dir.rs b/src/fs/dir.rs index a02c3e2..a1e93c6 100644 --- a/src/fs/dir.rs +++ b/src/fs/dir.rs @@ -10,7 +10,7 @@ use log::*; 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. /// /// This object gets passed to the Files themselves, in order for them to @@ -39,8 +39,8 @@ impl Dir { info!("Reading directory {:?}", &path); let contents = fs::read_dir(&path)? - .map(|result| result.map(|entry| entry.path())) - .collect::>()?; + .map(|result| result.map(|entry| entry.path())) + .collect::>()?; Ok(Self { contents, path }) } @@ -53,7 +53,8 @@ impl Dir { dir: self, dotfiles: dots.shows_dotfiles(), dots: dots.dots(), - git, git_ignoring, + git, + git_ignoring, } } @@ -106,7 +107,9 @@ impl<'dir, 'ig> Files<'dir, 'ig> { loop { if let Some(path) = self.inner.next() { let filename = File::filename(path); - if !self.dotfiles && filename.starts_with('.') { continue } + if ! self.dotfiles && filename.starts_with('.') { + continue; + } if self.git_ignoring { let git_status = self.git.map(|g| g.get(path, false)).unwrap_or_default(); @@ -139,7 +142,6 @@ enum DotsNext { Files, } - impl<'dir, 'ig> Iterator for Files<'dir, 'ig> { type Item = Result, (PathBuf, io::Error)>; @@ -149,22 +151,24 @@ impl<'dir, 'ig> Iterator for Files<'dir, 'ig> { self.dots = DotsNext::DotDot; Some(File::new_aa_current(self.dir) .map_err(|e| (Path::new(".").to_path_buf(), e))) - }, + } + DotsNext::DotDot => { self.dots = DotsNext::Files; Some(File::new_aa_parent(self.parent(), self.dir) .map_err(|e| (self.parent(), e))) - }, + } + DotsNext::Files => { self.next_visible_file() - }, + } } } } /// 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. #[derive(PartialEq, Debug, Copy, Clone)] pub enum DotFilter { @@ -199,9 +203,9 @@ impl DotFilter { /// Whether this filter should add dot directories to a listing. fn dots(self) -> DotsNext { 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, } } } diff --git a/src/fs/feature/git.rs b/src/fs/feature/git.rs index 490f18b..88fcbc0 100644 --- a/src/fs/feature/git.rs +++ b/src/fs/feature/git.rs @@ -36,7 +36,9 @@ impl GitCache { use std::iter::FromIterator; impl FromIterator for GitCache { - fn from_iter>(iter: I) -> Self { + fn from_iter(iter: I) -> Self + where I: IntoIterator + { let iter = iter.into_iter(); let mut git = Self { repos: Vec::with_capacity(iter.size_hint().0), @@ -61,8 +63,10 @@ impl FromIterator for GitCache { debug!("Discovered new Git repo"); git.repos.push(r); - }, - Err(miss) => git.misses.push(miss), + } + Err(miss) => { + git.misses.push(miss) + } } } } @@ -72,8 +76,6 @@ impl FromIterator for GitCache { } - - /// A **Git repository** is one we’ve discovered somewhere on the filesystem. pub struct GitRepo { @@ -99,7 +101,9 @@ pub struct GitRepo { enum GitContents { /// 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 /// repository out of the `Before` variant. @@ -107,7 +111,9 @@ enum GitContents { /// The data we’ve extracted from the repository, but only after we’ve /// actually done so. - After { statuses: Git } + After { + statuses: Git, + }, } impl GitRepo { @@ -116,7 +122,7 @@ impl GitRepo { /// depending on the prefix-lookup flag) and returns its Git status. /// /// Actually querying the `git2` repository for the mapping of paths to - /// Git statuses is only done once, and gets cached so we don't need to + /// Git statuses is only done once, and gets cached so we don’t need to /// re-query the entire repository the times after that. /// /// The temporary `Processing` enum variant is used after the `git2` @@ -166,7 +172,7 @@ impl GitRepo { let workdir = workdir.to_path_buf(); let contents = Mutex::new(GitContents::Before { repo }); Ok(Self { contents, workdir, original_path: path, extra_paths: Vec::new() }) - }, + } None => { warn!("Repository has no workdir?"); Err(path) @@ -205,8 +211,10 @@ fn repo_to_statuses(repo: &git2::Repository, workdir: &Path) -> Git { let elem = (path, e.status()); statuses.push(elem); } - }, - Err(e) => error!("Error looking up Git statuses: {:?}", e), + } + Err(e) => { + error!("Error looking up Git statuses: {:?}", e) + } } Git { statuses } @@ -217,7 +225,7 @@ fn repo_to_statuses(repo: &git2::Repository, workdir: &Path) -> Git { // 20.311276 INFO:exa::fs::feature::git: Getting Git statuses for repo with workdir "/vagrant/" // 20.799610 DEBUG:exa::output::table: Getting Git status for file "./Cargo.toml" // -// 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. @@ -239,6 +247,7 @@ impl Git { /// Get the status for the file at the given path. fn file_status(&self, file: &Path) -> f::Git { let path = reorient(file); + self.statuses.iter() .find(|p| p.0.as_path() == path) .map(|&(_, s)| f::Git { staged: index_status(s), unstaged: working_tree_status(s) }) @@ -250,25 +259,31 @@ impl Git { /// directories, which don’t really have an ‘official’ status. fn dir_status(&self, dir: &Path) -> f::Git { let path = reorient(dir); - let s = self.statuses.iter() - .filter(|p| p.0.starts_with(&path)) - .fold(git2::Status::empty(), |a, b| a | b.1); - f::Git { staged: index_status(s), unstaged: working_tree_status(s) } + let s = self.statuses.iter() + .filter(|p| p.0.starts_with(&path)) + .fold(git2::Status::empty(), |a, b| a | b.1); + + let staged = index_status(s); + let unstaged = working_tree_status(s); + f::Git { staged, unstaged } } } + /// Converts a path to an absolute path based on the current directory. /// 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 /// “/vagrant/README.md”, prefixed by the workdir. fn reorient(path: &Path) -> PathBuf { use std::env::current_dir; - // I’m not 100% on this func tbh + + // TODO: I’m not 100% on this func tbh 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) } diff --git a/src/fs/feature/mod.rs b/src/fs/feature/mod.rs index 62c76c1..c4fc20e 100644 --- a/src/fs/feature/mod.rs +++ b/src/fs/feature/mod.rs @@ -1,8 +1,9 @@ pub mod xattr; -#[cfg(feature="git")] pub mod git; +#[cfg(feature = "git")] +pub mod git; -#[cfg(not(feature="git"))] +#[cfg(not(feature = "git"))] pub mod git { use std::iter::FromIterator; use std::path::{Path, PathBuf}; @@ -13,8 +14,10 @@ pub mod git { pub struct GitCache; impl FromIterator for GitCache { - fn from_iter>(_iter: I) -> Self { - GitCache + fn from_iter(_iter: I) -> Self + where I: IntoIterator + { + Self } } diff --git a/src/fs/feature/xattr.rs b/src/fs/feature/xattr.rs index ea718b4..acf3098 100644 --- a/src/fs/feature/xattr.rs +++ b/src/fs/feature/xattr.rs @@ -1,4 +1,5 @@ //! Extended attribute support for Darwin and Linux systems. + #![allow(trivial_casts)] // for ARM extern crate libc; @@ -6,7 +7,11 @@ use std::cmp::Ordering; use std::io; use std::path::Path; -pub const ENABLED: bool = cfg!(feature="git") && cfg!(any(target_os="macos", target_os="linux")); + +pub const ENABLED: bool = + cfg!(feature="git") && + cfg!(any(target_os = "macos", target_os = "linux")); + pub trait FileAttributes { fn attributes(&self) -> io::Result>; @@ -27,20 +32,21 @@ impl FileAttributes for Path { #[cfg(not(any(target_os = "macos", target_os = "linux")))] impl FileAttributes for Path { fn attributes(&self) -> io::Result> { - Ok(vec![]) + Ok(Vec::new()) } fn symlink_attributes(&self) -> io::Result> { - Ok(vec![]) + Ok(Vec::new()) } } + /// Attributes which can be passed to `Attribute::list_with_flags` #[cfg(any(target_os = "macos", target_os = "linux"))] #[derive(Copy, Clone)] pub enum FollowSymlinks { Yes, - No + No, } /// Extended attribute @@ -50,29 +56,32 @@ pub struct Attribute { pub size: usize, } + #[cfg(any(target_os = "macos", target_os = "linux"))] pub fn list_attrs(lister: &lister::Lister, path: &Path) -> io::Result> { use std::ffi::CString; - let c_path = match path.to_str().and_then(|s| { CString::new(s).ok() }) { + let c_path = match path.to_str().and_then(|s| CString::new(s).ok()) { Some(cstring) => cstring, - None => return Err(io::Error::new(io::ErrorKind::Other, "Error: path somehow contained a NUL?")), + None => { + return Err(io::Error::new(io::ErrorKind::Other, "Error: path somehow contained a NUL?")); + } }; let bufsize = lister.listxattr_first(&c_path); match 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 buf = vec![0_u8; bufsize as usize]; let err = lister.listxattr_second(&c_path, &mut buf, bufsize); match err.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(); @@ -91,33 +100,40 @@ pub fn list_attrs(lister: &lister::Lister, path: &Path) -> io::Result 0 { names.push(Attribute { name: lister.translate_attribute_name(&buf[start..end]), - size: size as usize + size: size as usize, }); } start = c_end; } } + Ok(names) } + #[cfg(target_os = "macos")] mod lister { - use std::ffi::CString; - use libc::{c_int, size_t, ssize_t, c_char, c_void}; use super::FollowSymlinks; + use libc::{c_int, size_t, ssize_t, c_char, c_void}; + use std::ffi::CString; use std::ptr; extern "C" { fn listxattr( - path: *const c_char, namebuf: *mut c_char, - size: size_t, options: c_int + path: *const c_char, + namebuf: *mut c_char, + size: size_t, + options: c_int, ) -> ssize_t; fn getxattr( - path: *const c_char, name: *const c_char, - value: *mut c_void, size: size_t, position: u32, - options: c_int + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, + position: u32, + options: c_int, ) -> ssize_t; } @@ -128,24 +144,25 @@ mod lister { impl Lister { pub fn new(do_follow: FollowSymlinks) -> Self { let c_flags: c_int = match do_follow { - FollowSymlinks::Yes => 0x0001, - FollowSymlinks::No => 0x0000, + FollowSymlinks::Yes => 0x0001, + FollowSymlinks::No => 0x0000, }; Self { c_flags } } pub fn translate_attribute_name(&self, input: &[u8]) -> String { - use std::str::from_utf8_unchecked; - - unsafe { - from_utf8_unchecked(input).into() - } + unsafe { std::str::from_utf8_unchecked(input).into() } } pub fn listxattr_first(&self, c_path: &CString) -> ssize_t { unsafe { - listxattr(c_path.as_ptr(), ptr::null_mut(), 0, self.c_flags) + listxattr( + c_path.as_ptr(), + ptr::null_mut(), + 0, + self.c_flags, + ) } } @@ -154,7 +171,8 @@ mod lister { listxattr( c_path.as_ptr(), buf.as_mut_ptr() as *mut c_char, - bufsize as size_t, self.c_flags + bufsize as size_t, + self.c_flags, ) } } @@ -164,13 +182,17 @@ mod lister { getxattr( c_path.as_ptr(), buf.as_ptr() as *const c_char, - ptr::null_mut(), 0, 0, self.c_flags + ptr::null_mut(), + 0, + 0, + self.c_flags, ) } } } } + #[cfg(target_os = "linux")] mod lister { use std::ffi::CString; @@ -180,21 +202,29 @@ mod lister { extern "C" { fn listxattr( - path: *const c_char, list: *mut c_char, size: size_t + 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 + path: *const c_char, + list: *mut c_char, + size: size_t, ) -> ssize_t; fn getxattr( - path: *const c_char, name: *const c_char, - value: *mut c_void, size: size_t + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, ) -> ssize_t; fn lgetxattr( - path: *const c_char, name: *const c_char, - value: *mut c_void, size: size_t + path: *const c_char, + name: *const c_char, + value: *mut c_void, + size: size_t, ) -> ssize_t; } @@ -213,41 +243,46 @@ mod lister { pub fn listxattr_first(&self, c_path: &CString) -> ssize_t { let listxattr = match self.follow_symlinks { - FollowSymlinks::Yes => listxattr, - FollowSymlinks::No => llistxattr, + FollowSymlinks::Yes => listxattr, + FollowSymlinks::No => llistxattr, }; unsafe { - listxattr(c_path.as_ptr() as *const _, ptr::null_mut(), 0) + listxattr( + c_path.as_ptr() as *const _, + ptr::null_mut(), + 0, + ) } } pub fn listxattr_second(&self, c_path: &CString, buf: &mut Vec, bufsize: ssize_t) -> ssize_t { let listxattr = match self.follow_symlinks { - FollowSymlinks::Yes => listxattr, - FollowSymlinks::No => llistxattr, + FollowSymlinks::Yes => listxattr, + FollowSymlinks::No => llistxattr, }; unsafe { listxattr( c_path.as_ptr() as *const _, buf.as_mut_ptr() as *mut c_char, - bufsize as size_t + bufsize as size_t, ) } } pub fn getxattr(&self, c_path: &CString, buf: &[u8]) -> ssize_t { let getxattr = match self.follow_symlinks { - FollowSymlinks::Yes => getxattr, - FollowSymlinks::No => lgetxattr, + FollowSymlinks::Yes => getxattr, + FollowSymlinks::No => lgetxattr, }; unsafe { getxattr( c_path.as_ptr() as *const _, buf.as_ptr() as *const c_char, - ptr::null_mut(), 0 + ptr::null_mut(), + 0, ) } } diff --git a/src/fs/fields.rs b/src/fs/fields.rs index 4d3cb86..434a164 100644 --- a/src/fs/fields.rs +++ b/src/fs/fields.rs @@ -1,4 +1,3 @@ - //! Wrapper types for the values returned from `File`s. //! //! The methods of `File` that return information about the entry on the @@ -45,7 +44,14 @@ pub type uid_t = u32; /// Its ordering is used when sorting by type. #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] pub enum Type { - Directory, File, Link, Pipe, Socket, CharDevice, BlockDevice, Special, + Directory, + File, + Link, + Pipe, + Socket, + CharDevice, + BlockDevice, + Special, } impl Type { @@ -152,7 +158,7 @@ pub enum Size { /// have a file size. For example, a directory will just contain a list of /// its files as its “contents” and will be specially flagged as being a /// directory, rather than a file. However, seeing the “file size” of this - /// data is rarely useful -- I can’t think of a time when I’ve seen it and + /// data is rarely useful — I can’t think of a time when I’ve seen it and /// learnt something. So we discard it and just output “-” instead. /// /// See this answer for more: http://unix.stackexchange.com/a/68266 @@ -214,10 +220,11 @@ pub enum GitStatus { /// A file that’s ignored (that matches a line in .gitignore) Ignored, - /// A file that's updated but unmerged. + /// A file that’s updated but unmerged. Conflicted, } + /// 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 /// file’s status for both of these. @@ -227,11 +234,13 @@ pub struct Git { pub unstaged: GitStatus, } -use std::default::Default; impl Default for Git { /// Create a Git status for a file with nothing done to it. fn default() -> Self { - Self { staged: GitStatus::NotModified, unstaged: GitStatus::NotModified } + Self { + staged: GitStatus::NotModified, + unstaged: GitStatus::NotModified, + } } } diff --git a/src/fs/file.rs b/src/fs/file.rs index 5657588..dce5219 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -2,7 +2,7 @@ use std::io::Error as IOError; use std::io::Result as IOResult; -use std::os::unix::fs::{MetadataExt, PermissionsExt, FileTypeExt}; +use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt}; use std::path::{Path, PathBuf}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -11,7 +11,8 @@ use log::*; use crate::fs::dir::Dir; use crate::fs::fields as f; -/// A **File** is a wrapper around one of Rust's Path objects, along with + +/// A **File** is a wrapper around one of Rust’s `PathBuf` values, along with /// associated data about the file. /// /// Each file is definitely going to have its filename displayed at least @@ -44,7 +45,7 @@ pub struct File<'dir> { /// /// This too is queried multiple times, and is *not* cached by the OS, as /// it could easily change between invocations — but exa is so short-lived - /// it's better to just cache it. + /// it’s better to just cache it. pub metadata: std::fs::Metadata, /// A reference to the directory that contains this file, if any. @@ -60,7 +61,7 @@ pub struct File<'dir> { /// Whether this is one of the two `--all all` directories, `.` and `..`. /// /// Unlike all other entries, these are not returned as part of the - /// directory's children, and are in fact added specifically by exa; this + /// directory’s children, and are in fact added specifically by exa; this /// means that they should be skipped when recursing. pub is_all_all: bool, } @@ -88,8 +89,9 @@ impl<'dir> File<'dir> { debug!("Statting file {:?}", &path); let metadata = std::fs::symlink_metadata(&path)?; let is_all_all = true; + let parent_dir = Some(parent_dir); - Ok(File { path, parent_dir: Some(parent_dir), metadata, ext, name: ".".to_string(), is_all_all }) + Ok(File { path, parent_dir, metadata, ext, name: ".".into(), is_all_all }) } pub fn new_aa_parent(path: PathBuf, parent_dir: &'dir Dir) -> IOResult> { @@ -98,8 +100,9 @@ impl<'dir> File<'dir> { debug!("Statting file {:?}", &path); let metadata = std::fs::symlink_metadata(&path)?; let is_all_all = true; + let parent_dir = Some(parent_dir); - Ok(File { path, parent_dir: Some(parent_dir), metadata, ext, name: "..".to_string(), is_all_all }) + Ok(File { path, parent_dir, metadata, ext, name: "..".into(), is_all_all }) } /// A file’s name is derived from its string. This needs to handle directories @@ -127,7 +130,9 @@ impl<'dir> File<'dir> { fn ext(path: &Path) -> Option { 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()) } /// Whether this file is a directory on the filesystem. @@ -249,7 +254,8 @@ impl<'dir> File<'dir> { Ok(metadata) => { let ext = File::ext(&path); let name = File::filename(&path); - FileTarget::Ok(Box::new(File { parent_dir: None, path, ext, metadata, name, is_all_all: false })) + let file = File { parent_dir: None, path, ext, metadata, name, is_all_all: false }; + FileTarget::Ok(Box::new(file)) } Err(e) => { error!("Error following link {:?}: {:#?}", &path, e); @@ -274,14 +280,14 @@ impl<'dir> File<'dir> { } } - /// This file's inode. + /// This file’s inode. pub fn inode(&self) -> f::Inode { f::Inode(self.metadata.ino()) } - /// This file's number of filesystem blocks. + /// This file’s number of filesystem blocks. /// - /// (Not the size of each block, which we don't actually report on) + /// (Not the size of each block, which we don’t actually report on) pub fn blocks(&self) -> f::Blocks { if self.is_file() || self.is_link() { f::Blocks::Some(self.metadata.blocks()) @@ -334,17 +340,19 @@ impl<'dir> File<'dir> { pub fn changed_time(&self) -> Option { let (mut sec, mut nsec) = (self.metadata.ctime(), self.metadata.ctime_nsec()); - Some( - if sec < 0 { - if nsec > 0 { - sec += 1; - nsec -= 1_000_000_000; - } - UNIX_EPOCH - Duration::new(sec.abs() as u64, nsec.abs() as u32) - } else { - UNIX_EPOCH + Duration::new(sec as u64, nsec as u32) - } - ) + if sec < 0 { + if nsec > 0 { + sec += 1; + nsec -= 1_000_000_000; + } + + let duration = Duration::new(sec.abs() as u64, nsec.abs() as u32); + Some(UNIX_EPOCH - duration) + } + else { + let duration = Duration::new(sec as u64, nsec as u32); + Some(UNIX_EPOCH + duration) + } } /// This file’s last accessed timestamp, if available on this platform. @@ -392,7 +400,7 @@ impl<'dir> File<'dir> { /// This file’s permissions, with flags for each bit. pub fn permissions(&self) -> f::Permissions { let bits = self.metadata.mode(); - let has_bit = |bit| { bits & bit == bit }; + let has_bit = |bit| bits & bit == bit; f::Permissions { user_read: has_bit(modes::USER_READ), @@ -423,7 +431,7 @@ impl<'dir> File<'dir> { } } - /// Whether this file's name, including extension, is any of the strings + /// Whether this file’s name, including extension, is any of the strings /// that get passed in. pub fn name_is_one_of(&self, choices: &[&str]) -> bool { choices.contains(&&self.name[..]) @@ -455,7 +463,7 @@ pub enum FileTarget<'dir> { // Err is its own variant, instead of having the whole thing be inside an // `IOResult`, 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> { @@ -471,9 +479,10 @@ impl<'dir> FileTarget<'dir> { /// More readable aliases for the permission bits exposed by libc. #[allow(trivial_numeric_casts)] mod modes { - pub type Mode = u32; + // The `libc::mode_t` type’s actual type varies, but the value returned // from `metadata.permissions().mode()` is always `u32`. + pub type Mode = u32; pub const USER_READ: Mode = libc::S_IRUSR as Mode; pub const USER_WRITE: Mode = libc::S_IWUSR as Mode; diff --git a/src/fs/filter.rs b/src/fs/filter.rs index 26c5385..a902798 100644 --- a/src/fs/filter.rs +++ b/src/fs/filter.rs @@ -5,8 +5,8 @@ use std::iter::FromIterator; use std::os::unix::fs::MetadataExt; use std::path::Path; -use crate::fs::File; use crate::fs::DotFilter; +use crate::fs::File; /// The **file filter** processes a list of files before displaying them to @@ -88,12 +88,11 @@ pub struct FileFilter { pub git_ignore: GitIgnore, } - impl FileFilter { /// Remove every file in the given vector that does *not* pass the /// filter predicate for files found inside a directory. pub fn filter_child_files(&self, files: &mut Vec) { - files.retain(|f| !self.ignore_patterns.is_ignored(&f.name)); + files.retain(|f| ! self.ignore_patterns.is_ignored(&f.name)); if self.only_dirs { files.retain(File::is_directory); @@ -110,14 +109,18 @@ impl FileFilter { /// `exa -I='*.ogg' music/*` should filter out the ogg files obtained /// from the glob, even though the globbing is done by the shell! pub fn filter_argument_files(&self, files: &mut Vec) { - 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. pub fn sort_files<'a, F>(&self, files: &mut Vec) - where F: AsRef> { - - files.sort_by(|a, b| self.sort_field.compare_files(a.as_ref(), b.as_ref())); + where F: AsRef> + { + files.sort_by(|a, b| { + self.sort_field.compare_files(a.as_ref(), b.as_ref()) + }); if self.reverse { files.reverse(); @@ -126,8 +129,9 @@ impl FileFilter { if self.list_dirs_first { // This relies on the fact that `sort_by` is *stable*: it will keep // adjacent elements next to each other. - files.sort_by(|a, b| {b.as_ref().points_to_directory() - .cmp(&a.as_ref().points_to_directory()) + files.sort_by(|a, b| { + b.as_ref().points_to_directory() + .cmp(&a.as_ref().points_to_directory()) }); } } @@ -175,13 +179,13 @@ pub enum SortField { /// The time the file was changed (the “ctime”). /// /// This field is used to mark the time when a file’s metadata - /// changed -- its permissions, owners, or link count. + /// changed — its permissions, owners, or link count. /// /// In original Unix, this was, however, meant as creation time. /// https://www.bell-labs.com/usr/dmr/www/cacm.html ChangedDate, - /// The time the file was created (the "btime" or "birthtime"). + /// The time the file was created (the “btime” or “birthtime”). CreatedDate, /// The type of the file: directories, links, pipes, regular, files, etc. @@ -280,11 +284,8 @@ impl SortField { } fn strip_dot(n: &str) -> &str { - if n.starts_with('.') { - &n[1..] - } else { - n - } + if n.starts_with('.') { &n[1..] } + else { n } } } @@ -298,8 +299,12 @@ pub struct IgnorePatterns { } impl FromIterator for IgnorePatterns { - fn from_iter>(iter: I) -> Self { - Self { patterns: iter.into_iter().collect() } + + fn from_iter(iter: I) -> Self + where I: IntoIterator + { + let patterns = iter.into_iter().collect(); + Self { patterns } } } @@ -371,7 +376,6 @@ pub enum GitIgnore { // > usually found in $XDG_CONFIG_HOME/git/ignore. - #[cfg(test)] mod test_ignores { use super::*; diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 3275ccf..1188f61 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -4,7 +4,7 @@ pub use self::dir::{Dir, DotFilter}; mod file; pub use self::file::{File, FileTarget}; +pub mod dir_action; pub mod feature; pub mod fields; pub mod filter; -pub mod dir_action; diff --git a/src/info/filetype.rs b/src/info/filetype.rs index 3c5afeb..a23a39f 100644 --- a/src/info/filetype.rs +++ b/src/info/filetype.rs @@ -124,11 +124,17 @@ impl FileIcon for FileExtensions { fn icon_file(&self, file: &File) -> Option { use crate::output::icons::Icons; - Some(match file { - f if self.is_music(f) || self.is_lossless(f) => Icons::Audio.value(), - f if self.is_image(f) => Icons::Image.value(), - f if self.is_video(f) => Icons::Video.value(), - _ => return None, - }) + if self.is_music(file) || self.is_lossless(file) { + Some(Icons::Audio.value()) + } + else if self.is_image(file) { + Some(Icons::Image.value()) + } + else if self.is_video(file) { + Some(Icons::Video.value()) + } + else { + None + } } } diff --git a/src/info/sources.rs b/src/info/sources.rs index 042fdb4..fac5aa1 100644 --- a/src/info/sources.rs +++ b/src/info/sources.rs @@ -11,7 +11,7 @@ impl<'a> File<'a> { /// The point of this is to highlight compiled files such as `foo.js` when /// their source file `foo.coffee` exists in the same directory. /// For example, `foo.js` is perfectly valid without `foo.coffee`, so we - /// don't want to always blindly highlight `*.js` as compiled. + /// don’t want to always blindly highlight `*.js` as compiled. /// (See also `FileExtensions#is_compiled`) pub fn get_source_files(&self) -> Vec { if let Some(ext) = &self.ext { @@ -34,7 +34,7 @@ impl<'a> File<'a> { } } else { - vec![] // No source files if there's no extension, either! + vec![] // No source files if there’s no extension, either! } } } diff --git a/src/logger.rs b/src/logger.rs index 4f89eb1..b3c33c5 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -57,10 +57,10 @@ impl log::Log for Logger { 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"), + 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"), } } diff --git a/src/main.rs b/src/main.rs index 3b4df40..52b7795 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,11 +11,10 @@ use ansi_term::{ANSIStrings, Style}; use log::*; use crate::fs::{Dir, File}; -use crate::fs::filter::GitIgnore; use crate::fs::feature::git::GitCache; +use crate::fs::filter::GitIgnore; use crate::options::{Options, Vars}; -pub use crate::options::vars; -pub use crate::options::Misfire; +pub use crate::options::{Misfire, vars}; use crate::output::{escape, lines, grid, grid_details, details, View, Mode}; mod fs; @@ -35,18 +34,24 @@ fn main() { match Exa::from_args(args.iter(), stdout()) { Ok(mut exa) => { match exa.run() { - Ok(exit_status) => exit(exit_status), + Ok(exit_status) => { + exit(exit_status) + } + Err(e) => { match e.kind() { - ErrorKind::BrokenPipe => exit(exits::SUCCESS), + ErrorKind::BrokenPipe => { + exit(exits::SUCCESS); + } + _ => { eprintln!("{}", e); exit(exits::RUNTIME_ERROR); - }, + } }; } }; - }, + } Err(ref e) if e.is_error() => { let mut stderr = stderr(); @@ -57,13 +62,13 @@ fn main() { } exit(exits::OPTIONS_ERROR); - }, + } Err(ref e) => { println!("{}", e); exit(exits::SUCCESS); - }, - }; + } + } } @@ -109,7 +114,7 @@ fn git_options(options: &Options, args: &[&OsStr]) -> Option { impl<'args> Exa<'args> { pub fn from_args(args: I, writer: Stdout) -> Result, Misfire> - where I: Iterator + where I: Iterator { let (options, mut args) = Options::parse(args, &LiveVars)?; debug!("Dir action from arguments: {:#?}", options.dir_action); @@ -136,18 +141,19 @@ impl<'args> Exa<'args> { Err(e) => { exit_status = 2; writeln!(stderr(), "{:?}: {}", file_path, e)?; - }, + } + 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() { match f.to_dir() { - Ok(d) => dirs.push(d), - Err(e) => writeln!(stderr(), "{:?}: {}", file_path, e)?, + Ok(d) => dirs.push(d), + Err(e) => writeln!(stderr(), "{:?}: {}", file_path, e)?, } } else { files.push(f); } - }, + } } } @@ -176,7 +182,7 @@ impl<'args> Exa<'args> { writeln!(&mut self.writer)?; } - if !is_only_dir { + if ! is_only_dir { let mut bits = Vec::new(); escape(dir.path.display().to_string(), &mut bits, Style::default(), Style::default()); writeln!(&mut self.writer, "{}:", ANSIStrings(&bits))?; @@ -196,10 +202,10 @@ impl<'args> Exa<'args> { 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) { + if ! recurse_opts.tree && ! recurse_opts.is_too_deep(depth) { 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() { Ok(d) => child_dirs.push(d), Err(e) => writeln!(stderr(), "{}: {}", child_dir.path.display(), e)?, @@ -225,43 +231,42 @@ impl<'args> Exa<'args> { /// For various annoying logistical reasons, each one handles /// printing differently... fn print_files(&mut self, dir: Option<&Dir>, files: Vec) -> IOResult<()> { - if !files.is_empty() { - let View { ref mode, ref colours, ref style } = self.options.view; - - match mode { - Mode::Lines(ref opts) => { - let r = lines::Render { files, colours, style, opts }; - r.render(&mut self.writer) - } - - Mode::Grid(ref opts) => { - let r = grid::Render { files, colours, style, opts }; - r.render(&mut self.writer) - } - - Mode::Details(ref opts) => { - let filter = &self.options.filter; - let recurse = self.options.dir_action.recurse_options(); - - let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore; - let r = details::Render { dir, files, colours, style, opts, filter, recurse, git_ignoring }; - r.render(self.git.as_ref(), &mut self.writer) - } - - Mode::GridDetails(ref opts) => { - let grid = &opts.grid; - let filter = &self.options.filter; - let details = &opts.details; - let row_threshold = opts.row_threshold; - - let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore; - let r = grid_details::Render { dir, files, colours, style, grid, details, filter, row_threshold, git_ignoring }; - r.render(self.git.as_ref(), &mut self.writer) - } - } + if files.is_empty() { + return Ok(()); } - else { - Ok(()) + + let View { ref mode, ref colours, ref style } = self.options.view; + + match mode { + Mode::Lines(ref opts) => { + let r = lines::Render { files, colours, style, opts }; + r.render(&mut self.writer) + } + + Mode::Grid(ref opts) => { + let r = grid::Render { files, colours, style, opts }; + r.render(&mut self.writer) + } + + Mode::Details(ref opts) => { + let filter = &self.options.filter; + let recurse = self.options.dir_action.recurse_options(); + + let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore; + let r = details::Render { dir, files, colours, style, opts, filter, recurse, git_ignoring }; + r.render(self.git.as_ref(), &mut self.writer) + } + + Mode::GridDetails(ref opts) => { + let grid = &opts.grid; + let filter = &self.options.filter; + let details = &opts.details; + let row_threshold = opts.row_threshold; + + let git_ignoring = self.options.filter.git_ignore == GitIgnore::CheckAndIgnore; + let r = grid_details::Render { dir, files, colours, style, grid, details, filter, row_threshold, git_ignoring }; + r.render(self.git.as_ref(), &mut self.writer) + } } } } diff --git a/src/options/dir_action.rs b/src/options/dir_action.rs index 7316ddf..c16cff2 100644 --- a/src/options/dir_action.rs +++ b/src/options/dir_action.rs @@ -19,7 +19,7 @@ impl DirAction { if matches.is_strict() { // Early check for --level when it wouldn’t do anything - if !recurse && !tree && matches.count(&flags::LEVEL) > 0 { + if ! recurse && ! tree && matches.count(&flags::LEVEL) > 0 { return Err(Misfire::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE)); } else if recurse && as_file { diff --git a/src/options/filter.rs b/src/options/filter.rs index 4d248e7..fd21b6f 100644 --- a/src/options/filter.rs +++ b/src/options/filter.rs @@ -12,13 +12,13 @@ impl FileFilter { /// Determines which of all the file filter options to use. pub fn deduce(matches: &MatchedFlags) -> Result { Ok(Self { - list_dirs_first: matches.has(&flags::DIRS_FIRST)?, - reverse: matches.has(&flags::REVERSE)?, - only_dirs: matches.has(&flags::ONLY_DIRS)?, - sort_field: SortField::deduce(matches)?, - dot_filter: DotFilter::deduce(matches)?, - ignore_patterns: IgnorePatterns::deduce(matches)?, - git_ignore: GitIgnore::deduce(matches)?, + list_dirs_first: matches.has(&flags::DIRS_FIRST)?, + reverse: matches.has(&flags::REVERSE)?, + only_dirs: matches.has(&flags::ONLY_DIRS)?, + sort_field: SortField::deduce(matches)?, + dot_filter: DotFilter::deduce(matches)?, + ignore_patterns: IgnorePatterns::deduce(matches)?, + git_ignore: GitIgnore::deduce(matches)?, }) } } @@ -42,29 +42,64 @@ impl SortField { }; 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” // 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 // 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 // newest files) get sorted at the top, and files with the most // age (the oldest) at the bottom. - "age" | "old" | "oldest" => Self::ModifiedAge, - "ch" | "changed" => Self::ChangedDate, - "acc" | "accessed" => Self::AccessedDate, - "cr" | "created" => Self::CreatedDate, - "inode" => Self::FileInode, - "type" => Self::FileType, - "none" => Self::Unsorted, - _ => return Err(Misfire::BadArgument(&flags::SORT, word.into())) + "age" | "old" | "oldest" => { + Self::ModifiedAge + } + + "ch" | "changed" => { + Self::ChangedDate + } + "acc" | "accessed" => { + Self::AccessedDate + } + "cr" | "created" => { + Self::CreatedDate + } + "inode" => { + Self::FileInode + } + "type" => { + Self::FileType + } + "none" => { + Self::Unsorted + } + _ => { + return Err(Misfire::BadArgument(&flags::SORT, word.into())); + } }; Ok(field) @@ -103,7 +138,6 @@ impl SortField { // “apps” first, then “Documents”. // // You can get the old behaviour back by sorting with `--sort=Name`. - impl Default for SortField { fn default() -> Self { Self::Name(SortCase::AaBbCc) @@ -151,8 +185,8 @@ impl IgnorePatterns { // If there are no inputs, we return a set of patterns that doesn’t // match anything, rather than, say, `None`. let inputs = match matches.get(&flags::IGNORE_GLOB)? { - None => return Ok(Self::empty()), - Some(is) => is, + Some(is) => is, + None => return Ok(Self::empty()), }; // Awkwardly, though, a glob pattern can be invalid, and we need to @@ -162,8 +196,8 @@ impl IgnorePatterns { // It can actually return more than one glob error, // but we only use one. (TODO) match errors.pop() { - Some(e) => Err(e.into()), - None => Ok(patterns), + Some(e) => Err(e.into()), + None => Ok(patterns), } } } @@ -171,13 +205,16 @@ impl IgnorePatterns { impl GitIgnore { pub fn deduce(matches: &MatchedFlags) -> Result { - Ok(if matches.has(&flags::GIT_IGNORE)? { Self::CheckAndIgnore } - else { Self::Off }) + if matches.has(&flags::GIT_IGNORE)? { + Ok(Self::CheckAndIgnore) + } + else { + Ok(Self::Off) + } } } - #[cfg(test)] mod test { use super::*; diff --git a/src/options/flags.rs b/src/options/flags.rs index b4e24d2..88d53da 100644 --- a/src/options/flags.rs +++ b/src/options/flags.rs @@ -1,4 +1,4 @@ -use crate::options::parser::{Arg, Args, Values, TakesValue}; +use crate::options::parser::{Arg, Args, TakesValue, Values}; // exa options @@ -32,8 +32,8 @@ pub static GIT_IGNORE: Arg = Arg { short: None, long: "git-ignore", t pub static DIRS_FIRST: Arg = Arg { short: None, long: "group-directories-first", takes_value: TakesValue::Forbidden }; pub static ONLY_DIRS: Arg = Arg { short: Some(b'D'), long: "only-dirs", takes_value: TakesValue::Forbidden }; const SORTS: Values = &[ "name", "Name", "size", "extension", - "Extension", "modified", "changed", "accessed", - "created", "inode", "type", "none" ]; + "Extension", "modified", "changed", "accessed", + "created", "inode", "type", "none" ]; // display options pub static BINARY: Arg = Arg { short: Some(b'b'), long: "binary", takes_value: TakesValue::Forbidden }; diff --git a/src/options/help.rs b/src/options/help.rs index d279c8c..4bb551c 100644 --- a/src/options/help.rs +++ b/src/options/help.rs @@ -1,8 +1,8 @@ use std::fmt; +use crate::fs::feature::xattr; use crate::options::flags; use crate::options::parser::MatchedFlags; -use crate::fs::feature::xattr; static OPTIONS: &str = r##" @@ -106,7 +106,7 @@ impl fmt::Display for HelpString { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { writeln!(f, "Usage:\n exa [options] [files...]")?; - if !self.only_long { + if ! self.only_long { write!(f, "{}", OPTIONS)?; } @@ -127,7 +127,6 @@ impl fmt::Display for HelpString { } - #[cfg(test)] mod test { use crate::options::Options; diff --git a/src/options/misfire.rs b/src/options/misfire.rs index b42294b..2bfae85 100644 --- a/src/options/misfire.rs +++ b/src/options/misfire.rs @@ -6,7 +6,7 @@ use crate::options::{flags, HelpString, VersionString}; use crate::options::parser::{Arg, Flag, ParseError}; -/// A **misfire** is a thing that can happen instead of listing files -- a +/// A **misfire** is a thing that can happen instead of listing files — a /// catch-all for anything outside the program’s normal execution. #[derive(PartialEq, Debug)] pub enum Misfire { @@ -34,7 +34,7 @@ pub enum Misfire { Conflict(&'static Arg, &'static Arg), /// An option was given that does nothing when another one either is or - /// isn't present. + /// isn’t present. Useless(&'static Arg, bool, &'static Arg), /// An option was given that does nothing when either of two other options @@ -78,19 +78,19 @@ impl fmt::Display for Misfire { write!(f, "Option {} has no {:?} setting", arg, attempt) } }, - Self::InvalidOptions(e) => write!(f, "{}", e), - Self::Unsupported(e) => write!(f, "{}", e), - Self::Help(text) => write!(f, "{}", text), - Self::Version(version) => write!(f, "{}", version), - Self::Conflict(a, b) => write!(f, "Option {} conflicts with option {}", a, b), - Self::Duplicate(a, b) if a == b => write!(f, "Flag {} was given twice", a), - Self::Duplicate(a, b) => write!(f, "Flag {} conflicts with flag {}", a, b), - Self::Useless(a, false, b) => write!(f, "Option {} is useless without option {}", a, b), - Self::Useless(a, true, b) => write!(f, "Option {} is useless given option {}", a, b), - Self::Useless2(a, b1, b2) => write!(f, "Option {} is useless without options {} or {}", a, b1, b2), - Self::TreeAllAll => write!(f, "Option --tree is useless given --all --all"), - Self::FailedParse(ref e) => write!(f, "Failed to parse number: {}", e), - Self::FailedGlobPattern(ref e) => write!(f, "Failed to parse glob pattern: {}", e), + Self::InvalidOptions(e) => write!(f, "{}", e), + Self::Unsupported(e) => write!(f, "{}", e), + Self::Help(text) => write!(f, "{}", text), + Self::Version(version) => write!(f, "{}", version), + Self::Conflict(a, b) => write!(f, "Option {} conflicts with option {}", a, b), + Self::Duplicate(a, b) if a == b => write!(f, "Flag {} was given twice", a), + Self::Duplicate(a, b) => write!(f, "Flag {} conflicts with flag {}", a, b), + Self::Useless(a, false, b) => write!(f, "Option {} is useless without option {}", a, b), + Self::Useless(a, true, b) => write!(f, "Option {} is useless given option {}", a, b), + Self::Useless2(a, b1, b2) => write!(f, "Option {} is useless without options {} or {}", a, b1, b2), + Self::TreeAllAll => write!(f, "Option --tree is useless given --all --all"), + Self::FailedParse(ref e) => write!(f, "Failed to parse number: {}", e), + Self::FailedGlobPattern(ref e) => write!(f, "Failed to parse glob pattern: {}", e), } } } diff --git a/src/options/mod.rs b/src/options/mod.rs index dd9896c..ba25a0e 100644 --- a/src/options/mod.rs +++ b/src/options/mod.rs @@ -60,7 +60,7 @@ //! //! `--sort=size` should override `--sort=Name` because it’s closer to the end //! of the arguments array. In fact, because there’s no way to tell where the -//! arguments came from -- it’s just a heuristic -- this will still work even +//! arguments came from — it’s just a heuristic — this will still work even //! if no aliases are being used! //! //! Finally, this isn’t just useful when options could override each other. @@ -72,12 +72,13 @@ use std::ffi::{OsStr, OsString}; 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}; -mod style; mod dir_action; mod filter; +mod flags; +mod style; mod view; mod help; @@ -93,7 +94,6 @@ pub mod vars; pub use self::vars::Vars; mod parser; -mod flags; use self::parser::MatchedFlags; @@ -120,8 +120,9 @@ impl Options { /// for extra options. #[allow(unused_results)] pub fn parse<'args, I, V>(args: I, vars: &V) -> Result<(Self, Vec<&'args OsStr>), Misfire> - where I: IntoIterator, - V: Vars { + where I: IntoIterator, + V: Vars + { use crate::options::parser::{Matches, Strictness}; let strictness = match vars.get(vars::EXA_STRICT) { @@ -169,7 +170,6 @@ impl Options { } - #[cfg(test)] pub mod test { use super::{Options, Misfire, flags}; diff --git a/src/options/parser.rs b/src/options/parser.rs index 99f5ab8..7d2cd6c 100644 --- a/src/options/parser.rs +++ b/src/options/parser.rs @@ -70,8 +70,8 @@ impl Flag { impl fmt::Display for Flag { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 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), } } } @@ -144,7 +144,8 @@ impl Args { /// Iterates over the given list of command-line arguments and parses /// them into a list of matched flags and free strings. pub fn parse<'args, I>(&self, inputs: I, strictness: Strictness) -> Result, ParseError> - where I: IntoIterator { + where I: IntoIterator + { use std::os::unix::ffi::OsStrExt; let mut parsing = true; @@ -164,7 +165,7 @@ impl Args { // This allows a file named “--arg” to be specified by passing in // the pair “-- --arg”, without it getting matched as a flag that // doesn’t exist. - if !parsing { + if ! parsing { frees.push(arg) } else if arg == "--" { @@ -348,7 +349,7 @@ pub struct Matches<'args> { pub flags: MatchedFlags<'args>, /// All the strings that weren’t matched as arguments, as well as anything - /// after the special "--" string. + /// after the special “--” string. pub frees: Vec<&'args OsStr>, } @@ -373,7 +374,8 @@ impl<'a> MatchedFlags<'a> { /// Returns `true` if it was, `false` if it wasn’t, and an error in /// strict mode if it was specified more than once. pub fn has(&self, arg: &'static Arg) -> Result { - self.has_where(|flag| flag.matches(arg)).map(|flag| flag.is_some()) + self.has_where(|flag| flag.matches(arg)) + .map(|flag| flag.is_some()) } /// Returns the first found argument that satisfies the predicate, or @@ -488,7 +490,7 @@ fn split_on_equals(input: &OsStr) -> Option<(&OsStr, &OsStr)> { let (before, after) = input.as_bytes().split_at(index); // The after string contains the = that we need to remove. - if !before.is_empty() && after.len() >= 2 { + if ! before.is_empty() && after.len() >= 2 { return Some((OsStr::from_bytes(before), OsStr::from_bytes(&after[1..]))) } @@ -569,7 +571,9 @@ mod parse_test { let strictness = Strictness::UseLastArguments; // this isn’t even used let got = Args(TEST_ARGS).parse(inputs.iter(), strictness); - let expected = Ok(Matches { frees, flags: MatchedFlags { flags, strictness } }); + let flags = MatchedFlags { flags, strictness }; + + let expected = Ok(Matches { frees, flags }); assert_eq!(got, expected); } }; @@ -580,9 +584,11 @@ mod parse_test { use self::ParseError::*; let strictness = Strictness::UseLastArguments; // this isn’t even used - let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::>(); - let got = Args(TEST_ARGS).parse(bits.iter(), strictness); + let bits = $inputs.as_ref().into_iter() + .map(|&o| os(o)) + .collect::>(); + let got = Args(TEST_ARGS).parse(bits.iter(), strictness); assert_eq!(got, Err($error)); } }; @@ -719,6 +725,6 @@ mod matches_test { fn no_count() { let flags = MatchedFlags { flags: Vec::new(), strictness: Strictness::UseLastArguments }; - assert!(!flags.has(&COUNT).unwrap()); + assert_eq!(flags.has(&COUNT).unwrap(), false); } } diff --git a/src/options/style.rs b/src/options/style.rs index 1dbddbc..c877276 100644 --- a/src/options/style.rs +++ b/src/options/style.rs @@ -3,7 +3,7 @@ use ansi_term::Style; use crate::fs::File; use crate::options::{flags, Vars, Misfire}; use crate::options::parser::MatchedFlags; -use crate::output::file_name::{FileStyle, Classify}; +use crate::output::file_name::{Classify, FileStyle}; use crate::style::Colours; @@ -38,10 +38,9 @@ impl TerminalColours { /// Determine which terminal colour conditions to use. fn deduce(matches: &MatchedFlags) -> Result { - let word = match matches.get_where(|f| f.matches(&flags::COLOR) || f.matches(&flags::COLOUR))? { - Some(w) => w, - None => return Ok(Self::default()), + Some(w) => w, + None => return Ok(Self::default()), }; if word == "always" { @@ -77,7 +76,7 @@ pub struct Styles { impl Styles { - #[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 deduce(matches: &MatchedFlags, vars: &V, widther: TW) -> Result where TW: Fn() -> Option, V: Vars { use crate::info::filetype::FileExtensions; @@ -89,12 +88,12 @@ impl Styles { // custom colours at all let tc = TerminalColours::deduce(matches)?; - if tc == TerminalColours::Never - || (tc == TerminalColours::Automatic && widther().is_none()) - { + if tc == TerminalColours::Never || (tc == TerminalColours::Automatic && widther().is_none()) { + let exts = Box::new(NoFileColours); + return Ok(Self { colours: Colours::plain(), - style: FileStyle { classify, exts: Box::new(NoFileColours) }, + style: FileStyle { classify, exts }, }); } @@ -133,11 +132,16 @@ fn parse_color_vars(vars: &V, colours: &mut Colours) -> (ExtensionMappi if let Some(lsc) = vars.get(vars::LS_COLORS) { let lsc = lsc.to_string_lossy(); + LSColors(lsc.as_ref()).each_pair(|pair| { - if !colours.set_ls(&pair) { + if ! colours.set_ls(&pair) { match glob::Pattern::new(pair.key) { - Ok(pat) => exts.add(pat, pair.to_style()), - Err(e) => warn!("Couldn't parse glob pattern {:?}: {}", pair.key, e), + Ok(pat) => { + exts.add(pat, pair.to_style()); + } + Err(e) => { + warn!("Couldn't parse glob pattern {:?}: {}", pair.key, e); + } } } }); @@ -154,10 +158,14 @@ fn parse_color_vars(vars: &V, colours: &mut Colours) -> (ExtensionMappi } LSColors(exa.as_ref()).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) { - Ok(pat) => exts.add(pat, pair.to_style()), - Err(e) => warn!("Couldn't parse glob pattern {:?}: {}", pair.key, e), + Ok(pat) => { + exts.add(pat, pair.to_style()); + } + Err(e) => { + warn!("Couldn't parse glob pattern {:?}: {}", pair.key, e); + } } }; }); @@ -169,7 +177,7 @@ fn parse_color_vars(vars: &V, colours: &mut Colours) -> (ExtensionMappi #[derive(PartialEq, Debug, Default)] struct ExtensionMappings { - mappings: Vec<(glob::Pattern, Style)> + mappings: Vec<(glob::Pattern, Style)>, } // Loop through backwards so that colours specified later in the list override @@ -178,9 +186,7 @@ struct ExtensionMappings { use crate::output::file_name::FileColours; impl FileColours for ExtensionMappings { fn colour_file(&self, file: &File) -> Option