diff --git a/src/app/add.rs b/src/app/add.rs index 725f32f..7dff860 100644 --- a/src/app/add.rs +++ b/src/app/add.rs @@ -5,29 +5,35 @@ use crate::util; use anyhow::{bail, Result}; +use std::path::Path; + impl Run for Add { fn run(&self) -> Result<()> { - let path = if config::zo_resolve_symlinks() { + let path = if config::resolve_symlinks() { util::canonicalize(&self.path) } else { util::resolve_path(&self.path) }?; - - if config::zo_exclude_dirs()?.iter().any(|pattern| pattern.matches_path(&path)) { - return Ok(()); - } - - if !path.is_dir() { - bail!("not a directory: {}", path.display()); - } let path = util::path_to_str(&path)?; let now = util::current_time()?; - let data_dir = config::zo_data_dir()?; - let max_age = config::zo_maxage()?; + // 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 mut exclude_dirs = config::exclude_dirs()?.into_iter(); + if exclude_dirs.any(|pattern| pattern.matches(path)) || path.contains(EXCLUDE_CHARS) { + return Ok(()); + } + if !Path::new(path).is_dir() { + bail!("not a directory: {}", path); + } + + let data_dir = config::data_dir()?; + let max_age = config::maxage()?; let mut db = DatabaseFile::new(data_dir); let mut db = db.open()?; + db.add(path, now); db.age(max_age); diff --git a/src/app/import.rs b/src/app/import.rs index 736aaa7..883e6c8 100644 --- a/src/app/import.rs +++ b/src/app/import.rs @@ -10,7 +10,7 @@ use std::path::Path; impl Run for Import { fn run(&self) -> Result<()> { - let data_dir = config::zo_data_dir()?; + let data_dir = config::data_dir()?; let mut db = DatabaseFile::new(data_dir); let db = &mut db.open()?; diff --git a/src/app/init.rs b/src/app/init.rs index e4ac5db..64f3be6 100644 --- a/src/app/init.rs +++ b/src/app/init.rs @@ -12,8 +12,8 @@ impl Run for Init { fn run(&self) -> Result<()> { let cmd = if self.no_aliases { None } else { Some(self.cmd.as_str()) }; - let echo = config::zo_echo(); - let resolve_symlinks = config::zo_resolve_symlinks(); + let echo = config::echo(); + let resolve_symlinks = config::resolve_symlinks(); let opts = &Opts { cmd, hook: self.hook, echo, resolve_symlinks }; diff --git a/src/app/query.rs b/src/app/query.rs index d936e56..3dfee24 100644 --- a/src/app/query.rs +++ b/src/app/query.rs @@ -11,14 +11,14 @@ use std::io::{self, Write}; impl Run for Query { fn run(&self) -> Result<()> { - let data_dir = config::zo_data_dir()?; + let data_dir = config::data_dir()?; let mut db = DatabaseFile::new(data_dir); let mut db = db.open()?; let now = util::current_time()?; let mut stream = db.stream(now).with_keywords(&self.keywords); if !self.all { - let resolve_symlinks = config::zo_resolve_symlinks(); + let resolve_symlinks = config::resolve_symlinks(); stream = stream.with_exists(resolve_symlinks); } if let Some(path) = &self.exclude { diff --git a/src/app/remove.rs b/src/app/remove.rs index 906a3ba..99eb48c 100644 --- a/src/app/remove.rs +++ b/src/app/remove.rs @@ -11,7 +11,7 @@ use std::io::Write; impl Run for Remove { fn run(&self) -> Result<()> { - let data_dir = config::zo_data_dir()?; + let data_dir = config::data_dir()?; let mut db = DatabaseFile::new(data_dir); let mut db = db.open()?; diff --git a/src/config.rs b/src/config.rs index a9ae1fc..85e310a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,68 +8,67 @@ use std::env; use std::ffi::OsString; use std::path::PathBuf; -pub fn zo_data_dir() -> Result { - let data_dir = match env::var_os("_ZO_DATA_DIR") { - Some(data_osstr) => PathBuf::from(data_osstr), +pub fn data_dir() -> Result { + let path = match env::var_os("_ZO_DATA_DIR") { + Some(path) => PathBuf::from(path), None => match dirs::data_local_dir() { - Some(mut data_dir) => { - data_dir.push("zoxide"); - data_dir + Some(mut path) => { + path.push("zoxide"); + path } None => bail!("could not find data directory, please set _ZO_DATA_DIR manually"), }, }; - Ok(data_dir) + Ok(path) } -pub fn zo_echo() -> bool { +pub fn echo() -> bool { match env::var_os("_ZO_ECHO") { Some(var) => var == "1", None => false, } } -pub fn zo_exclude_dirs() -> Result> { +pub fn exclude_dirs() -> Result> { match env::var_os("_ZO_EXCLUDE_DIRS") { - Some(dirs_osstr) => env::split_paths(&dirs_osstr) + Some(paths) => env::split_paths(&paths) .map(|path| { let pattern = path.to_str().context("invalid unicode in _ZO_EXCLUDE_DIRS")?; - Pattern::new(&pattern) + Pattern::new(pattern) .with_context(|| format!("invalid glob in _ZO_EXCLUDE_DIRS: {}", pattern)) }) .collect(), None => { let pattern = (|| { let home = dirs::home_dir()?; - let home_str = home.to_str()?; - let home_esc = Pattern::escape(home_str); - Pattern::new(&home_esc).ok() + let home = home.to_str()?; + let home = Pattern::escape(home); + Pattern::new(&home).ok() })(); - Ok(pattern.into_iter().collect()) } } } -pub fn zo_fzf_opts() -> Option { +pub fn fzf_opts() -> Option { env::var_os("_ZO_FZF_OPTS") } -pub fn zo_maxage() -> Result { +pub fn maxage() -> Result { match env::var_os("_ZO_MAXAGE") { - Some(maxage_osstr) => { - let maxage_str = maxage_osstr.to_str().context("invalid unicode in _ZO_MAXAGE")?; - let maxage = maxage_str.parse::().with_context(|| { - format!("unable to parse _ZO_MAXAGE as integer: {}", maxage_str) - })?; + Some(maxage) => { + let maxage = maxage.to_str().context("invalid unicode in _ZO_MAXAGE")?; + let maxage = maxage + .parse::() + .with_context(|| format!("unable to parse _ZO_MAXAGE as integer: {}", maxage))?; Ok(maxage as Rank) } None => Ok(10000.0), } } -pub fn zo_resolve_symlinks() -> bool { +pub fn resolve_symlinks() -> bool { match env::var_os("_ZO_RESOLVE_SYMLINKS") { Some(var) => var == "1", None => false, diff --git a/src/db/mod.rs b/src/db/mod.rs index 138087b..3675cdd 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -7,7 +7,6 @@ pub use stream::Stream; use anyhow::{Context, Result}; use tempfile::{NamedTempFile, PersistError}; -use std::borrow::Cow; use std::fs; use std::io::{self, Write}; use std::path::{Path, PathBuf}; @@ -51,7 +50,7 @@ impl<'file> Database<'file> { match self.dirs.iter_mut().find(|dir| dir.path == path) { None => { - self.dirs.push(Dir { path: Cow::Owned(path.into()), last_accessed: now, rank: 1.0 }) + self.dirs.push(Dir { path: path.to_string().into(), last_accessed: now, rank: 1.0 }) } Some(dir) => { dir.last_accessed = now; diff --git a/src/db/stream.rs b/src/db/stream.rs index fd642ea..5386dab 100644 --- a/src/db/stream.rs +++ b/src/db/stream.rs @@ -89,7 +89,6 @@ impl<'db, 'file> Stream<'db, 'file> { if !self.check_exists { return true; } - let resolver = if self.resolve_symlinks { fs::symlink_metadata } else { fs::metadata }; resolver(path.as_ref()).map(|m| m.is_dir()).unwrap_or_default() } diff --git a/src/fzf.rs b/src/fzf.rs index a03685a..b8ddefd 100644 --- a/src/fzf.rs +++ b/src/fzf.rs @@ -17,7 +17,7 @@ impl Fzf { command.arg("-m"); } command.arg("-n2..").stdin(Stdio::piped()).stdout(Stdio::piped()); - if let Some(fzf_opts) = config::zo_fzf_opts() { + if let Some(fzf_opts) = config::fzf_opts() { command.env("FZF_DEFAULT_OPTS", fzf_opts); }