zoxide-remove should accept multiple arguments

This commit is contained in:
Ajeet D'Souza 2021-07-29 08:23:46 +05:30
parent 18a6052b51
commit 04950b2a58
10 changed files with 29 additions and 38 deletions

View File

@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- `zoxide add` now accepts multiple arguments. - `zoxide add` and `zoxide remove` now accept multiple arguments.
### Fixed ### Fixed

View File

@ -75,7 +75,7 @@ _arguments "${_arguments_options[@]}" \
'()*--interactive=[]' \ '()*--interactive=[]' \
'-h[Prints help information]' \ '-h[Prints help information]' \
'--help[Prints help information]' \ '--help[Prints help information]' \
'::path:_files -/' \ '*::paths:_files -/' \
&& ret=0 && ret=0
;; ;;
esac esac

View File

@ -127,7 +127,7 @@ _zoxide() {
return 0 return 0
;; ;;
zoxide__remove) zoxide__remove)
opts=" -i -h --interactive --help <path> " opts=" -i -h --interactive --help <paths>... "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0

View File

@ -2,7 +2,7 @@
.SH NAME .SH NAME
zoxide-remove - remove a directory from the database zoxide-remove - remove a directory from the database
.SH SYNOPSIS .SH SYNOPSIS
.B zoxide remove \fIPATH [OPTIONS]\fR .B zoxide remove \fI[PATHS] [OPTIONS]\fR
.SH DESCRIPTION .SH DESCRIPTION
If you'd like to permanently exclude a directory from the database, see the If you'd like to permanently exclude a directory from the database, see the
\fB_ZO_EXCLUDE_DIRS\fR environment variable in \fBzoxide\fR(1). \fB_ZO_EXCLUDE_DIRS\fR environment variable in \fBzoxide\fR(1).

View File

@ -126,12 +126,12 @@ pub struct Query {
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
pub struct Remove { pub struct Remove {
// Use interactive selection // Use interactive selection
#[clap(conflicts_with = "path", long, short, value_name = "keywords")] #[clap(conflicts_with = "paths", long, short, value_name = "keywords")]
pub interactive: Option<Vec<String>>, pub interactive: Option<Vec<String>>,
#[clap( #[clap(
conflicts_with = "interactive", conflicts_with = "interactive",
required_unless_present = "interactive", required_unless_present = "interactive",
value_hint = ValueHint::DirPath value_hint = ValueHint::DirPath
)] )]
pub path: Option<String>, pub paths: Vec<String>,
} }

View File

@ -42,6 +42,7 @@ impl Run for Add {
if db.modified { if db.modified {
db.age(max_age); db.age(max_age);
db.save()?;
} }
Ok(()) Ok(())

View File

@ -25,7 +25,7 @@ impl Run for Import {
} }
.context("import error")?; .context("import error")?;
Ok(()) db.save()
} }
} }

View File

@ -1,6 +1,6 @@
use crate::app::{Query, Run}; use crate::app::{Query, Run};
use crate::config; use crate::config;
use crate::db::DatabaseFile; use crate::db::{Database, DatabaseFile};
use crate::error::BrokenPipeHandler; use crate::error::BrokenPipeHandler;
use crate::fzf::Fzf; use crate::fzf::Fzf;
use crate::util; use crate::util;
@ -14,6 +14,12 @@ impl Run for Query {
let data_dir = config::data_dir()?; let data_dir = config::data_dir()?;
let mut db = DatabaseFile::new(data_dir); let mut db = DatabaseFile::new(data_dir);
let mut db = db.open()?; let mut db = db.open()?;
self.query(&mut db).and(db.save())
}
}
impl Query {
fn query(&self, db: &mut Database) -> Result<()> {
let now = util::current_time()?; let now = util::current_time()?;
let mut stream = db.stream(now).with_keywords(&self.keywords); let mut stream = db.stream(now).with_keywords(&self.keywords);

View File

@ -28,35 +28,25 @@ impl Run for Remove {
selection = fzf.wait_select()?; selection = fzf.wait_select()?;
let paths = selection.lines().filter_map(|line| line.get(5..)); let paths = selection.lines().filter_map(|line| line.get(5..));
let mut not_found = Vec::new();
for path in paths { for path in paths {
if !db.remove(&path) { if !db.remove(&path) {
not_found.push(path); bail!("path not found in database: {}", path);
} }
} }
if !not_found.is_empty() {
let mut err = "path not found in database:".to_string();
for path in not_found {
err.push_str("\n ");
err.push_str(path.as_ref());
}
bail!(err);
}
} }
None => { None => {
// unwrap is safe here because path is required_unless_present = "interactive" for path in self.paths.iter() {
let path = self.path.as_ref().unwrap(); if !db.remove(path) {
if !db.remove(path) { let path_abs = util::resolve_path(&path)?;
let path_abs = util::resolve_path(&path)?; let path_abs = util::path_to_str(&path_abs)?;
let path_abs = util::path_to_str(&path_abs)?; if path_abs != path && !db.remove(path_abs) {
if path_abs != path && !db.remove(path) { bail!("path not found in database: {} ({})", path, path_abs)
bail!("path not found in database:\n {}", &path) }
} }
} }
} }
} }
Ok(()) db.save()
} }
} }

View File

@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
pub struct Database<'file> { pub struct Database<'file> {
pub dirs: DirList<'file>, pub dirs: DirList<'file>,
pub modified: bool, pub modified: bool,
pub data_dir: &'file PathBuf, pub data_dir: &'file Path,
} }
impl<'file> Database<'file> { impl<'file> Database<'file> {
@ -125,16 +125,6 @@ impl<'file> Database<'file> {
} }
} }
impl Drop for Database<'_> {
fn drop(&mut self) {
// Since the error can't be properly handled here,
// pretty-print it instead.
if let Err(e) = self.save() {
let _ = writeln!(io::stderr(), "zoxide: {:?}", e);
}
}
}
#[cfg(windows)] #[cfg(windows)]
fn persist<P: AsRef<Path>>(mut file: NamedTempFile, path: P) -> Result<(), PersistError> { fn persist<P: AsRef<Path>>(mut file: NamedTempFile, path: P) -> Result<(), PersistError> {
use rand::distributions::{Distribution, Uniform}; use rand::distributions::{Distribution, Uniform};
@ -231,6 +221,7 @@ mod tests {
let mut db = db.open().unwrap(); let mut db = db.open().unwrap();
db.add(path, now); db.add(path, now);
db.add(path, now); db.add(path, now);
db.save().unwrap();
} }
{ {
let mut db = DatabaseFile::new(data_dir.path()); let mut db = DatabaseFile::new(data_dir.path());
@ -253,17 +244,20 @@ mod tests {
let mut db = DatabaseFile::new(data_dir.path()); let mut db = DatabaseFile::new(data_dir.path());
let mut db = db.open().unwrap(); let mut db = db.open().unwrap();
db.add(path, now); db.add(path, now);
db.save().unwrap();
} }
{ {
let mut db = DatabaseFile::new(data_dir.path()); let mut db = DatabaseFile::new(data_dir.path());
let mut db = db.open().unwrap(); let mut db = db.open().unwrap();
assert!(db.remove(path)); assert!(db.remove(path));
db.save().unwrap();
} }
{ {
let mut db = DatabaseFile::new(data_dir.path()); let mut db = DatabaseFile::new(data_dir.path());
let mut db = db.open().unwrap(); let mut db = db.open().unwrap();
assert!(db.dirs.is_empty()); assert!(db.dirs.is_empty());
assert!(!db.remove(path)); assert!(!db.remove(path));
db.save().unwrap();
} }
} }
} }