zoxide-remove should accept multiple arguments
This commit is contained in:
parent
18a6052b51
commit
04950b2a58
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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).
|
||||||
|
|
|
||||||
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(())
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ impl Run for Import {
|
||||||
}
|
}
|
||||||
.context("import error")?;
|
.context("import error")?;
|
||||||
|
|
||||||
Ok(())
|
db.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue