--basedir query option (#1027)
This commit is contained in:
parent
30129f4344
commit
261cf8846a
|
@ -120,6 +120,7 @@ _arguments "${_arguments_options[@]}" : \
|
|||
(query)
|
||||
_arguments "${_arguments_options[@]}" : \
|
||||
'--exclude=[Exclude the current directory]:path:_files -/' \
|
||||
'--base-dir=[Only search within this directory]:path:_files -/' \
|
||||
'-a[Show unavailable directories]' \
|
||||
'--all[Show unavailable directories]' \
|
||||
'(-l --list)-i[Use interactive selection]' \
|
||||
|
|
|
@ -102,6 +102,7 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
|
|||
}
|
||||
'zoxide;query' {
|
||||
[CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Exclude the current directory')
|
||||
[CompletionResult]::new('--base-dir', '--base-dir', [CompletionResultType]::ParameterName, 'Only search within this directory')
|
||||
[CompletionResult]::new('-a', '-a', [CompletionResultType]::ParameterName, 'Show unavailable directories')
|
||||
[CompletionResult]::new('--all', '--all', [CompletionResultType]::ParameterName, 'Show unavailable directories')
|
||||
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'Use interactive selection')
|
||||
|
|
|
@ -199,7 +199,7 @@ _zoxide() {
|
|||
return 0
|
||||
;;
|
||||
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 --base-dir --help --version [KEYWORDS]..."
|
||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
|
@ -212,6 +212,13 @@ _zoxide() {
|
|||
fi
|
||||
return 0
|
||||
;;
|
||||
--base-dir)
|
||||
COMPREPLY=()
|
||||
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
|
||||
compopt -o plusdirs
|
||||
fi
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=()
|
||||
;;
|
||||
|
|
|
@ -90,6 +90,7 @@ set edit:completion:arg-completer[zoxide] = {|@words|
|
|||
}
|
||||
&'zoxide;query'= {
|
||||
cand --exclude 'Exclude the current directory'
|
||||
cand --base-dir 'Only search within this directory'
|
||||
cand -a 'Show unavailable directories'
|
||||
cand --all 'Show unavailable directories'
|
||||
cand -i 'Use interactive selection'
|
||||
|
|
|
@ -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 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 base-dir -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 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'
|
||||
|
|
|
@ -82,6 +82,7 @@ module completions {
|
|||
--list(-l) # List all matching directories
|
||||
--score(-s) # Print score with results
|
||||
--exclude: path # Exclude the current directory
|
||||
--base-dir: path # Only search within this directory
|
||||
--help(-h) # Print help
|
||||
--version(-V) # Print version
|
||||
]
|
||||
|
|
|
@ -214,6 +214,16 @@ const completion: Fig.Spec = {
|
|||
template: "folders",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--base-dir",
|
||||
description: "Only search within this directory",
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "base_dir",
|
||||
isOptional: true,
|
||||
template: "folders",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: ["-a", "--all"],
|
||||
description: "Show unavailable directories",
|
||||
|
|
|
@ -186,6 +186,10 @@ pub struct Query {
|
|||
/// Exclude the current directory
|
||||
#[clap(long, value_hint = ValueHint::DirPath, value_name = "path")]
|
||||
pub exclude: Option<String>,
|
||||
|
||||
/// Only search within this directory
|
||||
#[clap(long, value_hint = ValueHint::DirPath, value_name = "path")]
|
||||
pub base_dir: Option<String>,
|
||||
}
|
||||
|
||||
/// Remove a directory from the database
|
||||
|
|
|
@ -79,7 +79,8 @@ impl Query {
|
|||
fn get_stream<'a>(&self, db: &'a mut Database, now: Epoch) -> Result<Stream<'a>> {
|
||||
let mut options = StreamOptions::new(now)
|
||||
.with_keywords(self.keywords.iter().map(|s| s.as_str()))
|
||||
.with_exclude(config::exclude_dirs()?);
|
||||
.with_exclude(config::exclude_dirs()?)
|
||||
.with_base_dir(self.base_dir.clone());
|
||||
if !self.all {
|
||||
let resolve_symlinks = config::resolve_symlinks();
|
||||
options = options.with_exists(true).with_resolve_symlinks(resolve_symlinks);
|
||||
|
|
|
@ -183,7 +183,7 @@ impl Database {
|
|||
*self.borrow_dirty()
|
||||
}
|
||||
|
||||
pub fn dirs(&self) -> &[Dir] {
|
||||
pub fn dirs(&self) -> &[Dir<'_>] {
|
||||
self.borrow_dirs()
|
||||
}
|
||||
|
||||
|
@ -203,7 +203,7 @@ impl Database {
|
|||
.context("could not serialize database")
|
||||
}
|
||||
|
||||
fn deserialize(bytes: &[u8]) -> Result<Vec<Dir>> {
|
||||
fn deserialize(bytes: &[u8]) -> Result<Vec<Dir<'_>>> {
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::iter::Rev;
|
||||
use std::ops::Range;
|
||||
use std::path::Path;
|
||||
use std::{fs, path};
|
||||
|
||||
use glob::Pattern;
|
||||
|
@ -20,7 +21,7 @@ impl<'a> Stream<'a> {
|
|||
Stream { db, idxs, options }
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> Option<&Dir> {
|
||||
pub fn next(&mut self) -> Option<&Dir<'_>> {
|
||||
while let Some(idx) = self.idxs.next() {
|
||||
let dir = &self.db.dirs()[idx];
|
||||
|
||||
|
@ -28,11 +29,16 @@ impl<'a> Stream<'a> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if !self.filter_by_base_dir(&dir.path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !self.filter_by_exclude(&dir.path) {
|
||||
self.db.swap_remove(idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exists queries are slow, this should always be checked last.
|
||||
if !self.filter_by_exists(&dir.path) {
|
||||
if dir.last_accessed < self.options.ttl {
|
||||
self.db.swap_remove(idx);
|
||||
|
@ -47,6 +53,30 @@ impl<'a> Stream<'a> {
|
|||
None
|
||||
}
|
||||
|
||||
fn filter_by_base_dir(&self, path: &str) -> bool {
|
||||
match &self.options.base_dir {
|
||||
Some(base_dir) => Path::new(path).starts_with(base_dir),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_by_exclude(&self, path: &str) -> bool {
|
||||
!self.options.exclude.iter().any(|pattern| pattern.matches(path))
|
||||
}
|
||||
|
||||
fn filter_by_exists(&self, path: &str) -> bool {
|
||||
if !self.options.exists {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The logic here is reversed - if we resolve symlinks when adding entries to
|
||||
// the database, we should not return symlinks when querying back from
|
||||
// the database.
|
||||
let resolver =
|
||||
if self.options.resolve_symlinks { fs::symlink_metadata } else { fs::metadata };
|
||||
resolver(path).map(|metadata| metadata.is_dir()).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn filter_by_keywords(&self, path: &str) -> bool {
|
||||
let (keywords_last, keywords) = match self.options.keywords.split_last() {
|
||||
Some(split) => split,
|
||||
|
@ -74,23 +104,6 @@ impl<'a> Stream<'a> {
|
|||
|
||||
true
|
||||
}
|
||||
|
||||
fn filter_by_exclude(&self, path: &str) -> bool {
|
||||
!self.options.exclude.iter().any(|pattern| pattern.matches(path))
|
||||
}
|
||||
|
||||
fn filter_by_exists(&self, path: &str) -> bool {
|
||||
if !self.options.exists {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The logic here is reversed - if we resolve symlinks when adding entries to
|
||||
// the database, we should not return symlinks when querying back from
|
||||
// the database.
|
||||
let resolver =
|
||||
if self.options.resolve_symlinks { fs::symlink_metadata } else { fs::metadata };
|
||||
resolver(path).map(|metadata| metadata.is_dir()).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StreamOptions {
|
||||
|
@ -112,6 +125,10 @@ pub struct StreamOptions {
|
|||
/// Directories that do not exist and haven't been accessed since TTL will
|
||||
/// be lazily removed.
|
||||
ttl: Epoch,
|
||||
|
||||
/// Only return directories within this parent directory
|
||||
/// Does not check if the path exists
|
||||
base_dir: Option<String>,
|
||||
}
|
||||
|
||||
impl StreamOptions {
|
||||
|
@ -123,6 +140,7 @@ impl StreamOptions {
|
|||
exists: false,
|
||||
resolve_symlinks: false,
|
||||
ttl: now.saturating_sub(3 * MONTH),
|
||||
base_dir: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,6 +167,11 @@ impl StreamOptions {
|
|||
self.resolve_symlinks = resolve_symlinks;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_base_dir(mut self, base_dir: Option<String>) -> Self {
|
||||
self.base_dir = base_dir;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -97,7 +97,7 @@ mod tests {
|
|||
#[apply(opts)]
|
||||
fn elvish_elvish(cmd: Option<&str>, hook: InitHook, echo: bool, resolve_symlinks: bool) {
|
||||
let opts = Opts { cmd, hook, echo, resolve_symlinks };
|
||||
let mut source = String::default();
|
||||
let mut source = String::new();
|
||||
|
||||
// Filter out lines using edit:*, since those functions are only available in
|
||||
// the interactive editor.
|
||||
|
|
|
@ -135,7 +135,7 @@ impl FzfChild {
|
|||
mem::drop(self.0.stdin.take());
|
||||
|
||||
let mut stdout = self.0.stdout.take().unwrap();
|
||||
let mut output = String::default();
|
||||
let mut output = String::new();
|
||||
stdout.read_to_string(&mut output).context("failed to read from fzf")?;
|
||||
|
||||
let status = self.0.wait().context("wait failed on fzf")?;
|
||||
|
|
Loading…
Reference in New Issue