feat: --basedir query option

This commit is contained in:
Azalea Colburn 2025-03-24 18:05:00 -07:00
parent 30129f4344
commit 6866c85e0a
No known key found for this signature in database
9 changed files with 55 additions and 2 deletions

View File

@ -120,6 +120,7 @@ _arguments "${_arguments_options[@]}" : \
(query) (query)
_arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \
'--exclude=[Exclude the current directory]:path:_files -/' \ '--exclude=[Exclude the current directory]:path:_files -/' \
'(--exclude)--basedir=[Only search within this directory]:path:_files -/' \
'-a[Show unavailable directories]' \ '-a[Show unavailable directories]' \
'--all[Show unavailable directories]' \ '--all[Show unavailable directories]' \
'(-l --list)-i[Use interactive selection]' \ '(-l --list)-i[Use interactive selection]' \

View File

@ -102,6 +102,7 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
} }
'zoxide;query' { 'zoxide;query' {
[CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Exclude the current directory') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Exclude the current directory')
[CompletionResult]::new('--basedir', '--basedir', [CompletionResultType]::ParameterName, 'Only search within this directory')
[CompletionResult]::new('-a', '-a', [CompletionResultType]::ParameterName, 'Show unavailable directories') [CompletionResult]::new('-a', '-a', [CompletionResultType]::ParameterName, 'Show unavailable directories')
[CompletionResult]::new('--all', '--all', [CompletionResultType]::ParameterName, 'Show unavailable directories') [CompletionResult]::new('--all', '--all', [CompletionResultType]::ParameterName, 'Show unavailable directories')
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'Use interactive selection') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'Use interactive selection')

View File

@ -199,7 +199,7 @@ _zoxide() {
return 0 return 0
;; ;;
zoxide__query) zoxide__query)
opts="-a -i -l -s -h -V --all --interactive --list --score --exclude --help --version [KEYWORDS]..." opts="-a -i -l -s -h -V --all --interactive --list --score --exclude --basedir --help --version [KEYWORDS]..."
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
@ -212,6 +212,13 @@ _zoxide() {
fi fi
return 0 return 0
;; ;;
--basedir)
COMPREPLY=()
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o plusdirs
fi
return 0
;;
*) *)
COMPREPLY=() COMPREPLY=()
;; ;;

View File

@ -90,6 +90,7 @@ set edit:completion:arg-completer[zoxide] = {|@words|
} }
&'zoxide;query'= { &'zoxide;query'= {
cand --exclude 'Exclude the current directory' cand --exclude 'Exclude the current directory'
cand --basedir 'Only search within this directory'
cand -a 'Show unavailable directories' cand -a 'Show unavailable directories'
cand --all 'Show unavailable directories' cand --all 'Show unavailable directories'
cand -i 'Use interactive selection' cand -i 'Use interactive selection'

View File

@ -62,6 +62,7 @@ complete -c zoxide -n "__fish_zoxide_using_subcommand init" -l no-cmd -d 'Preven
complete -c zoxide -n "__fish_zoxide_using_subcommand init" -s h -l help -d 'Print help' complete -c zoxide -n "__fish_zoxide_using_subcommand init" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand init" -s V -l version -d 'Print version' complete -c zoxide -n "__fish_zoxide_using_subcommand init" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand query" -l exclude -d 'Exclude the current directory' -r -f -a "(__fish_complete_directories)" complete -c zoxide -n "__fish_zoxide_using_subcommand query" -l exclude -d 'Exclude the current directory' -r -f -a "(__fish_complete_directories)"
complete -c zoxide -n "__fish_zoxide_using_subcommand query" -l basedir -d 'Only search within this directory' -r -f -a "(__fish_complete_directories)"
complete -c zoxide -n "__fish_zoxide_using_subcommand query" -s a -l all -d 'Show unavailable directories' complete -c zoxide -n "__fish_zoxide_using_subcommand query" -s a -l all -d 'Show unavailable directories'
complete -c zoxide -n "__fish_zoxide_using_subcommand query" -s i -l interactive -d 'Use interactive selection' complete -c zoxide -n "__fish_zoxide_using_subcommand query" -s i -l interactive -d 'Use interactive selection'
complete -c zoxide -n "__fish_zoxide_using_subcommand query" -s l -l list -d 'List all matching directories' complete -c zoxide -n "__fish_zoxide_using_subcommand query" -s l -l list -d 'List all matching directories'

View File

@ -214,6 +214,19 @@ const completion: Fig.Spec = {
template: "folders", template: "folders",
}, },
}, },
{
name: "--basedir",
description: "Only search within this directory",
exclusiveOn: [
"--exclude",
],
isRepeatable: true,
args: {
name: "basedir",
isOptional: true,
template: "folders",
},
},
{ {
name: ["-a", "--all"], name: ["-a", "--all"],
description: "Show unavailable directories", description: "Show unavailable directories",

View File

@ -186,6 +186,10 @@ pub struct Query {
/// Exclude the current directory /// Exclude the current directory
#[clap(long, value_hint = ValueHint::DirPath, value_name = "path")] #[clap(long, value_hint = ValueHint::DirPath, value_name = "path")]
pub exclude: Option<String>, pub exclude: Option<String>,
/// Only search within this directory
#[clap(long, value_hint = ValueHint::DirPath, value_name = "path", conflicts_with = "exclude")]
pub basedir: Option<String>,
} }
/// Remove a directory from the database /// Remove a directory from the database

View File

@ -79,7 +79,8 @@ impl Query {
fn get_stream<'a>(&self, db: &'a mut Database, now: Epoch) -> Result<Stream<'a>> { fn get_stream<'a>(&self, db: &'a mut Database, now: Epoch) -> Result<Stream<'a>> {
let mut options = StreamOptions::new(now) let mut options = StreamOptions::new(now)
.with_keywords(self.keywords.iter().map(|s| s.as_str())) .with_keywords(self.keywords.iter().map(|s| s.as_str()))
.with_exclude(config::exclude_dirs()?); .with_exclude(config::exclude_dirs()?)
.with_basedir(self.basedir.clone());
if !self.all { if !self.all {
let resolve_symlinks = config::resolve_symlinks(); let resolve_symlinks = config::resolve_symlinks();
options = options.with_exists(true).with_resolve_symlinks(resolve_symlinks); options = options.with_exists(true).with_resolve_symlinks(resolve_symlinks);

View File

@ -1,5 +1,6 @@
use std::iter::Rev; use std::iter::Rev;
use std::ops::Range; use std::ops::Range;
use std::path::{Path, PathBuf};
use std::{fs, path}; use std::{fs, path};
use glob::Pattern; use glob::Pattern;
@ -40,6 +41,10 @@ impl<'a> Stream<'a> {
continue; continue;
} }
if !self.filter_by_basedir(&dir.path) {
continue;
}
let dir = &self.db.dirs()[idx]; let dir = &self.db.dirs()[idx];
return Some(dir); return Some(dir);
} }
@ -91,6 +96,15 @@ impl<'a> Stream<'a> {
if self.options.resolve_symlinks { fs::symlink_metadata } else { fs::metadata }; if self.options.resolve_symlinks { fs::symlink_metadata } else { fs::metadata };
resolver(path).map(|metadata| metadata.is_dir()).unwrap_or_default() resolver(path).map(|metadata| metadata.is_dir()).unwrap_or_default()
} }
fn filter_by_basedir(&self, path: &str) -> bool {
if let Some(basedir) = &self.options.basedir {
let path = Path::new(path);
return path.starts_with(basedir);
}
true
}
} }
pub struct StreamOptions { pub struct StreamOptions {
@ -112,6 +126,10 @@ pub struct StreamOptions {
/// Directories that do not exist and haven't been accessed since TTL will /// Directories that do not exist and haven't been accessed since TTL will
/// be lazily removed. /// be lazily removed.
ttl: Epoch, ttl: Epoch,
/// Only return directories within this parent directory
/// Does not check if the path exists
basedir: Option<String>,
} }
impl StreamOptions { impl StreamOptions {
@ -123,6 +141,7 @@ impl StreamOptions {
exists: false, exists: false,
resolve_symlinks: false, resolve_symlinks: false,
ttl: now.saturating_sub(3 * MONTH), ttl: now.saturating_sub(3 * MONTH),
basedir: None,
} }
} }
@ -149,6 +168,11 @@ impl StreamOptions {
self.resolve_symlinks = resolve_symlinks; self.resolve_symlinks = resolve_symlinks;
self self
} }
pub fn with_basedir(mut self, basedir: Option<String>) -> Self {
self.basedir = basedir;
self
}
} }
#[cfg(test)] #[cfg(test)]