diff --git a/.cargo/config b/.cargo/config.toml similarity index 100% rename from .cargo/config rename to .cargo/config.toml diff --git a/build.rs b/build.rs index 720daac2..6f43dfa6 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,5 @@ -use std::env; -use std::io; use std::process::Command; +use std::{env, io}; fn main() { let pkg_version = env::var("CARGO_PKG_VERSION").unwrap(); @@ -10,8 +9,8 @@ fn main() { }; println!("cargo:rustc-env=ZOXIDE_VERSION={}", version); - // Since we are generating completions in the package directory, we need to - // set this so that Cargo doesn't rebuild every time. + // Since we are generating completions in the package directory, we need to set this so that + // Cargo doesn't rebuild every time. println!("cargo:rerun-if-changed=src"); println!("cargo:rerun-if-changed=templates"); println!("cargo:rerun-if-changed=tests"); diff --git a/rustfmt.toml b/rustfmt.toml index c0073690..450ab8a4 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,6 @@ +# comment_width = 100 +# error_on_line_overflow = true +# error_on_unformatted = true # group_imports = "StdExternalCrate" # imports_granularity = "Module" max_width = 120 @@ -6,3 +9,4 @@ use_field_init_shorthand = true use_small_heuristics = "Max" use_try_shorthand = true # wrap_comments = true +# version = "Two" diff --git a/src/app/_app.rs b/src/app/_app.rs index 32859c63..8e9baba1 100644 --- a/src/app/_app.rs +++ b/src/app/_app.rs @@ -1,7 +1,7 @@ -use clap::{AppSettings, ArgEnum, Clap, ValueHint}; - use std::path::PathBuf; +use clap::{AppSettings, ArgEnum, Clap, ValueHint}; + const ENV_HELP: &str = "ENVIRONMENT VARIABLES: _ZO_DATA_DIR Path for zoxide data files _ZO_ECHO Prints the matched directory before navigating to it when set to 1 diff --git a/src/app/add.rs b/src/app/add.rs index 6a63f0de..7477701f 100644 --- a/src/app/add.rs +++ b/src/app/add.rs @@ -1,16 +1,15 @@ -use crate::app::{Add, Run}; -use crate::config; -use crate::db::DatabaseFile; -use crate::util; +use std::path::Path; use anyhow::{bail, Result}; -use std::path::Path; +use crate::app::{Add, Run}; +use crate::db::DatabaseFile; +use crate::{config, util}; impl Run for Add { fn run(&self) -> Result<()> { - // These characters can't be printed cleanly to a single line, so they - // can cause confusion when writing to fzf / stdout. + // These characters can't be printed cleanly to a single line, so they can cause confusion + // when writing to fzf / stdout. const EXCLUDE_CHARS: &[char] = &['\n', '\r']; let data_dir = config::data_dir()?; @@ -22,11 +21,10 @@ impl Run for Add { let mut db = db.open()?; for path in &self.paths { - let path = if config::resolve_symlinks() { util::canonicalize(path) } else { util::resolve_path(path) }?; + let path = if config::resolve_symlinks() { util::canonicalize } else { util::resolve_path }(path)?; let path = util::path_to_str(&path)?; - // Ignore path if it contains unsupported characters, or if it's in - // the exclude list. + // Ignore path if it contains unsupported characters, or if it's in the exclude list. if path.contains(EXCLUDE_CHARS) || exclude_dirs.iter().any(|glob| glob.matches(path)) { continue; } diff --git a/src/app/import.rs b/src/app/import.rs index b1f573ba..90d66bc0 100644 --- a/src/app/import.rs +++ b/src/app/import.rs @@ -1,10 +1,10 @@ -use crate::app::{Import, ImportFrom, Run}; -use crate::config; -use crate::db::{Database, DatabaseFile, Dir}; +use std::fs; use anyhow::{bail, Context, Result}; -use std::fs; +use crate::app::{Import, ImportFrom, Run}; +use crate::config; +use crate::db::{Database, DatabaseFile, Dir}; impl Run for Import { fn run(&self) -> Result<()> { @@ -37,9 +37,8 @@ fn from_autojump<'a>(db: &mut Database<'a>, buffer: &'a str) -> Result<()> { let rank = split.next().with_context(|| format!("invalid entry: {}", line))?; let mut rank = rank.parse::().with_context(|| format!("invalid rank: {}", rank))?; - // Normalize the rank using a sigmoid function. Don't import actual - // ranks from autojump, since its scoring algorithm is very different, - // and might take a while to get normalized. + // Normalize the rank using a sigmoid function. Don't import actual ranks from autojump, + // since its scoring algorithm is very different and might take a while to get normalized. rank = sigmoid(rank); let path = split.next().with_context(|| format!("invalid entry: {}", line))?; diff --git a/src/app/init.rs b/src/app/init.rs index 64f3be6c..64186adf 100644 --- a/src/app/init.rs +++ b/src/app/init.rs @@ -1,12 +1,12 @@ -use crate::app::{Init, InitShell, Run}; -use crate::config; -use crate::error::BrokenPipeHandler; -use crate::shell::{self, Opts}; +use std::io::{self, Write}; use anyhow::{Context, Result}; use askama::Template; -use std::io::{self, Write}; +use crate::app::{Init, InitShell, Run}; +use crate::config; +use crate::error::BrokenPipeHandler; +use crate::shell::{self, Opts}; impl Run for Init { fn run(&self) -> Result<()> { diff --git a/src/app/mod.rs b/src/app/mod.rs index b6c17a2d..04c2fe19 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -5,10 +5,10 @@ mod init; mod query; mod remove; -pub use crate::app::_app::*; - use anyhow::Result; +pub use crate::app::_app::*; + pub trait Run { fn run(&self) -> Result<()>; } diff --git a/src/app/query.rs b/src/app/query.rs index ff230900..cb1de833 100644 --- a/src/app/query.rs +++ b/src/app/query.rs @@ -1,13 +1,12 @@ +use std::io::{self, Write}; + +use anyhow::{Context, Result}; + use crate::app::{Query, Run}; -use crate::config; use crate::db::{Database, DatabaseFile}; use crate::error::BrokenPipeHandler; use crate::fzf::Fzf; -use crate::util; - -use anyhow::{Context, Result}; - -use std::io::{self, Write}; +use crate::{config, util}; impl Run for Query { fn run(&self) -> Result<()> { diff --git a/src/app/remove.rs b/src/app/remove.rs index 29aa0ad5..18334712 100644 --- a/src/app/remove.rs +++ b/src/app/remove.rs @@ -1,13 +1,12 @@ +use std::io::Write; + +use anyhow::{bail, Result}; + use crate::app::{Remove, Run}; -use crate::config; use crate::db::DatabaseFile; use crate::error::BrokenPipeHandler; use crate::fzf::Fzf; -use crate::util; - -use anyhow::{bail, Result}; - -use std::io::Write; +use crate::{config, util}; impl Run for Remove { fn run(&self) -> Result<()> { diff --git a/src/config.rs b/src/config.rs index 9854fd3d..0ed2e564 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,12 +1,12 @@ -use crate::db::Rank; +use std::env; +use std::ffi::OsString; +use std::path::PathBuf; use anyhow::{bail, Context, Result}; use dirs_next as dirs; use glob::Pattern; -use std::env; -use std::ffi::OsString; -use std::path::PathBuf; +use crate::db::Rank; pub fn data_dir() -> Result { let path = match env::var_os("_ZO_DATA_DIR") { diff --git a/src/db/dir.rs b/src/db/dir.rs index d1aa8915..1661a1fe 100644 --- a/src/db/dir.rs +++ b/src/db/dir.rs @@ -1,11 +1,11 @@ -use anyhow::{bail, Context, Result}; -use bincode::Options as _; -use serde::{Deserialize, Serialize}; - use std::borrow::Cow; use std::fmt::{self, Display, Formatter}; use std::ops::{Deref, DerefMut}; +use anyhow::{bail, Context, Result}; +use bincode::Options as _; +use serde::{Deserialize, Serialize}; + #[derive(Debug, Deserialize, Serialize)] pub struct DirList<'a>(#[serde(borrow)] pub Vec>); @@ -17,8 +17,8 @@ impl DirList<'_> { } pub fn from_bytes(bytes: &[u8]) -> Result { - // Assume a maximum size for the database. This prevents bincode from - // throwing strange errors when it encounters invalid data. + // Assume a maximum size for the database. This prevents bincode from throwing strange + // errors when it encounters invalid data. const MAX_SIZE: u64 = 32 << 20; // 32 MiB let deserializer = &mut bincode::options().with_fixint_encoding().with_limit(MAX_SIZE); @@ -149,10 +149,10 @@ pub type Epoch = u64; #[cfg(test)] mod tests { - use super::{Dir, DirList}; - use std::borrow::Cow; + use super::{Dir, DirList}; + #[test] fn zero_copy() { let dirs = DirList(vec![Dir { path: "/".into(), rank: 0.0, last_accessed: 0 }]); diff --git a/src/db/mod.rs b/src/db/mod.rs index da49e524..7ae5fcb1 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,16 +1,15 @@ mod dir; mod stream; -pub use dir::{Dir, DirList, Epoch, Rank}; -pub use stream::Stream; - -use anyhow::{Context, Result}; -use tempfile::{NamedTempFile, PersistError}; - use std::fs; use std::io::{self, Write}; use std::path::{Path, PathBuf}; +use anyhow::{Context, Result}; +pub use dir::{Dir, DirList, Epoch, Rank}; +pub use stream::Stream; +use tempfile::{NamedTempFile, PersistError}; + #[derive(Debug)] pub struct Database<'file> { pub dirs: DirList<'file>, @@ -28,9 +27,8 @@ impl<'file> Database<'file> { let mut file = NamedTempFile::new_in(self.data_dir) .with_context(|| format!("could not create temporary database in: {}", self.data_dir.display()))?; - // Preallocate enough space on the file, preventing copying later on. - // This optimization may fail on some filesystems, but it is safe to - // ignore it and proceed. + // Preallocate enough space on the file, preventing copying later on. This optimization may + // fail on some filesystems, but it is safe to ignore it and proceed. let _ = file.as_file().set_len(buffer.len() as _); file.write_all(&buffer) .with_context(|| format!("could not write to temporary database: {}", file.path().display()))?; @@ -89,8 +87,8 @@ impl<'file> Database<'file> { Stream::new(self, now) } - /// Removes the directory with `path` from the store. - /// This does not preserve ordering, but is O(1). + /// Removes the directory with `path` from the store. This does not preserve ordering, but is + /// O(1). pub fn remove>(&mut self, path: S) -> bool { let path = path.as_ref(); @@ -124,15 +122,16 @@ impl<'file> Database<'file> { #[cfg(windows)] fn persist>(mut file: NamedTempFile, path: P) -> Result<(), PersistError> { + use std::thread; + use std::time::Duration; + use rand::distributions::{Distribution, Uniform}; use rand::rngs::SmallRng; use rand::SeedableRng; - use std::thread; - use std::time::Duration; - // File renames on Windows are not atomic and sometimes fail with `PermissionDenied`. - // This is extremely unlikely unless it's running in a loop on multiple threads. - // Nevertheless, we guard against it by retrying the rename a fixed number of times. + // File renames on Windows are not atomic and sometimes fail with `PermissionDenied`. This is + // extremely unlikely unless it's running in a loop on multiple threads. Nevertheless, we guard + // against it by retrying the rename a fixed number of times. const MAX_TRIES: usize = 10; let mut rng = None; @@ -170,9 +169,8 @@ impl DatabaseFile { } pub fn open(&mut self) -> Result { - // Read the entire database to memory. For smaller files, this is - // faster than mmap / streaming, and allows for zero-copy - // deserialization. + // Read the entire database to memory. For smaller files, this is faster than + // mmap / streaming, and allows for zero-copy deserialization. let path = db_path(&self.data_dir); match fs::read(&path) { Ok(buffer) => { @@ -182,9 +180,8 @@ impl DatabaseFile { Ok(Database { dirs, modified: false, data_dir: &self.data_dir }) } Err(e) if e.kind() == io::ErrorKind::NotFound => { - // Create data directory, but don't create any file yet. - // The file will be created later by [`Database::save`] - // if any data is modified. + // Create data directory, but don't create any file yet. The file will be created + // later by [`Database::save`] if any data is modified. fs::create_dir_all(&self.data_dir) .with_context(|| format!("unable to create data directory: {}", self.data_dir.display()))?; Ok(Database { dirs: DirList::new(), modified: false, data_dir: &self.data_dir }) diff --git a/src/db/stream.rs b/src/db/stream.rs index 6811c098..e5d3eb98 100644 --- a/src/db/stream.rs +++ b/src/db/stream.rs @@ -1,12 +1,11 @@ -use super::{Database, Dir, Epoch}; -use crate::util; +use std::iter::Rev; +use std::ops::Range; +use std::{fs, path}; use ordered_float::OrderedFloat; -use std::fs; -use std::iter::Rev; -use std::ops::Range; -use std::path; +use super::{Database, Dir, Epoch}; +use crate::util; pub struct Stream<'db, 'file> { db: &'db mut Database<'file>, @@ -27,8 +26,7 @@ impl<'db, 'file> Stream<'db, 'file> { db.dirs.sort_unstable_by_key(|dir| OrderedFloat(dir.score(now))); let idxs = (0..db.dirs.len()).rev(); - // If a directory is deleted and hasn't been used for 90 days, delete - // it from the database. + // If a directory is deleted and hasn't been used for 90 days, delete it from the database. let expire_below = now.saturating_sub(90 * 24 * 60 * 60); Stream { @@ -124,11 +122,11 @@ impl<'db, 'file> Stream<'db, 'file> { #[cfg(test)] mod tests { - use super::Database; + use std::path::PathBuf; use rstest::rstest; - use std::path::PathBuf; + use super::Database; #[rstest] // Case normalization diff --git a/src/error.rs b/src/error.rs index 34954d59..b4fd35a8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,9 +1,9 @@ -use anyhow::{bail, Context, Result}; - use std::fmt::{self, Display, Formatter}; use std::io; -// Custom error type for early exit. +use anyhow::{bail, Context, Result}; + +/// Custom error type for early exit. #[derive(Debug)] pub struct SilentExit { pub code: i32, diff --git a/src/fzf.rs b/src/fzf.rs index b8ddefdc..2123cfd9 100644 --- a/src/fzf.rs +++ b/src/fzf.rs @@ -1,10 +1,10 @@ -use crate::config; -use crate::error::SilentExit; +use std::io; +use std::process::{Child, ChildStdin, Command, Stdio}; use anyhow::{bail, Context, Result}; -use std::io; -use std::process::{Child, ChildStdin, Command, Stdio}; +use crate::config; +use crate::error::SilentExit; pub struct Fzf { child: Child, @@ -33,7 +33,7 @@ impl Fzf { } pub fn stdin(&mut self) -> &mut ChildStdin { - // unwrap is safe here because command.stdin() has been piped + // unwrap is safe here because command.stdin() has been piped. self.child.stdin.as_mut().unwrap() } diff --git a/src/main.rs b/src/main.rs index 3f8d0e74..cd7b33c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,14 +6,13 @@ mod fzf; mod shell; mod util; -use crate::app::{App, Run}; -use crate::error::SilentExit; +use std::io::{self, Write}; +use std::{env, process}; use clap::Clap; -use std::env; -use std::io::{self, Write}; -use std::process; +use crate::app::{App, Run}; +use crate::error::SilentExit; pub fn main() { // Forcibly disable backtraces. diff --git a/src/shell.rs b/src/shell.rs index 6765e7ee..c20acc33 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -35,12 +35,12 @@ make_template!(Zsh, "zsh.txt"); #[cfg(feature = "shell_tests")] #[cfg(test)] mod tests { - use super::*; - use askama::Template; use assert_cmd::Command; use rstest::rstest; + use super::*; + #[rstest] fn bash_bash( #[values(None, Some("z"))] cmd: Option<&str>, @@ -102,8 +102,8 @@ mod tests { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let mut source = String::new(); - // Filter out lines using edit:*, since those functions - // are only available in the interactive editor. + // Filter out lines using edit:*, since those functions are only available in the + // interactive editor. for line in Elvish(&opts).render().unwrap().split('\n').filter(|line| !line.contains("edit:")) { source.push_str(line); source.push('\n'); @@ -356,8 +356,7 @@ mod tests { let opts = Opts { cmd, hook, echo, resolve_symlinks }; let source = Zsh(&opts).render().unwrap(); - // ShellCheck doesn't support zsh yet. - // https://github.com/koalaman/shellcheck/issues/809 + // ShellCheck doesn't support zsh yet: https://github.com/koalaman/shellcheck/issues/809 Command::new("shellcheck") .args(&["--enable", "all", "--shell", "bash", "-"]) .write_stdin(source) diff --git a/src/util.rs b/src/util.rs index 6eb7e462..8f1b7e76 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,11 +1,11 @@ -use crate::db::Epoch; - -use anyhow::{bail, Context, Result}; - use std::env; use std::path::{Component, Path, PathBuf}; use std::time::SystemTime; +use anyhow::{bail, Context, Result}; + +use crate::db::Epoch; + pub fn canonicalize>(path: &P) -> Result { dunce::canonicalize(path).with_context(|| format!("could not resolve path: {}", path.as_ref().display())) } @@ -26,11 +26,8 @@ pub fn path_to_str>(path: &P) -> Result<&str> { path.to_str().with_context(|| format!("invalid unicode in path: {}", path.display())) } -/// Resolves the absolute version of a path. -/// -/// If path is already absolute, the path is still processed to be cleaned, as it can contained ".." or "." (or other) -/// character. -/// If path is relative, use the current directory to build the absolute path. +/// Returns the absolute version of a path. Like [`std::path::Path::canonicalize`], but doesn't +/// resolve symlinks. pub fn resolve_path>(path: &P) -> Result { let path = path.as_ref(); let base_path; @@ -135,7 +132,7 @@ pub fn resolve_path>(path: &P) -> Result { Ok(stack.iter().collect()) } -// Convert a string to lowercase, with a fast path for ASCII strings. +/// Convert a string to lowercase, with a fast path for ASCII strings. pub fn to_lowercase>(s: S) -> String { let s = s.as_ref(); if s.is_ascii() { diff --git a/tests/completion.rs b/tests/completion.rs index f7c6c4c6..2db66e88 100644 --- a/tests/completion.rs +++ b/tests/completion.rs @@ -9,10 +9,9 @@ fn completions_bash() { Command::new("bash").args(&["--noprofile", "--norc", "-c", source]).assert().success().stdout("").stderr(""); } -// Elvish: the completions file uses editor commands to add completions to the -// shell. However, Elvish does not support running editor commands from a -// script, so we can't create a test for this. -// +// Elvish: the completions file uses editor commands to add completions to the shell. However, +// Elvish does not support running editor commands from a script, so we can't create a test for +// this. See: https://github.com/elves/elvish/issues/1299 #[test] fn completions_fish() { diff --git a/xtask/src/main.rs b/xtask/src/main.rs index df53e818..fb3c18ad 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,7 +1,7 @@ -use clap::{ArgEnum, Clap}; - use std::process::Command; +use clap::{ArgEnum, Clap}; + #[derive(Clap, Debug)] struct App { #[clap(arg_enum)]