Remove --alias flag from add command and use a separate add-alias command instead

This commit is contained in:
Tahaa-Dev 2026-07-21 03:32:17 +03:00 committed by Taha Mahmoud
parent b3ae1e6a28
commit 5528680cc6
14 changed files with 212 additions and 92 deletions

View File

@ -32,8 +32,6 @@ _zoxide() {
_arguments "${_arguments_options[@]}" : \
'-s+[The rank to increment the entry if it exists or initialize it with if it doesn'\''t]:SCORE:_default' \
'--score=[The rank to increment the entry if it exists or initialize it with if it doesn'\''t]:SCORE:_default' \
'-a+[]:ALIAS:_default' \
'--alias=[]:ALIAS:_default' \
'-h[Print help]' \
'--help[Print help]' \
'-V[Print version]' \
@ -41,6 +39,17 @@ _arguments "${_arguments_options[@]}" : \
'*::paths:_files -/' \
&& ret=0
;;
(add-alias)
_arguments "${_arguments_options[@]}" : \
'-p+[]:PATH:_files -/' \
'--path=[]:PATH:_files -/' \
'-h[Print help]' \
'--help[Print help]' \
'-V[Print version]' \
'--version[Print version]' \
'*::aliases:_default' \
&& ret=0
;;
(edit)
_arguments "${_arguments_options[@]}" : \
'-h[Print help]' \
@ -221,6 +230,7 @@ esac
_zoxide_commands() {
local commands; commands=(
'add:Add a new directory or increment its rank' \
'add-alias:Add aliases for a directory' \
'edit:Edit the database' \
'import:Import entries from another application' \
'init:Generate shell configuration' \
@ -234,6 +244,11 @@ _zoxide__subcmd__add_commands() {
local commands; commands=()
_describe -t commands 'zoxide add commands' commands "$@"
}
(( $+functions[_zoxide__subcmd__add-alias_commands] )) ||
_zoxide__subcmd__add-alias_commands() {
local commands; commands=()
_describe -t commands 'zoxide add-alias commands' commands "$@"
}
(( $+functions[_zoxide__subcmd__edit_commands] )) ||
_zoxide__subcmd__edit_commands() {
local commands; commands=(

View File

@ -26,6 +26,7 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('add', 'add', [CompletionResultType]::ParameterValue, 'Add a new directory or increment its rank')
[CompletionResult]::new('add-alias', 'add-alias', [CompletionResultType]::ParameterValue, 'Add aliases for a directory')
[CompletionResult]::new('edit', 'edit', [CompletionResultType]::ParameterValue, 'Edit the database')
[CompletionResult]::new('import', 'import', [CompletionResultType]::ParameterValue, 'Import entries from another application')
[CompletionResult]::new('init', 'init', [CompletionResultType]::ParameterValue, 'Generate shell configuration')
@ -36,8 +37,15 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock {
'zoxide;add' {
[CompletionResult]::new('-s', '-s', [CompletionResultType]::ParameterName, 'The rank to increment the entry if it exists or initialize it with if it doesn''t')
[CompletionResult]::new('--score', '--score', [CompletionResultType]::ParameterName, 'The rank to increment the entry if it exists or initialize it with if it doesn''t')
[CompletionResult]::new('-a', '-a', [CompletionResultType]::ParameterName, 'a')
[CompletionResult]::new('--alias', '--alias', [CompletionResultType]::ParameterName, 'alias')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
break
}
'zoxide;add-alias' {
[CompletionResult]::new('-p', '-p', [CompletionResultType]::ParameterName, 'p')
[CompletionResult]::new('--path', '--path', [CompletionResultType]::ParameterName, 'path')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')

View File

@ -19,6 +19,9 @@ _zoxide() {
zoxide,add)
cmd="zoxide__subcmd__add"
;;
zoxide,add-alias)
cmd="zoxide__subcmd__add__subcmd__alias"
;;
zoxide,edit)
cmd="zoxide__subcmd__edit"
;;
@ -71,7 +74,7 @@ _zoxide() {
case "${cmd}" in
zoxide)
opts="-h -V --help --version add edit import init query remove"
opts="-h -V --help --version add add-alias edit import init query remove"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@ -85,7 +88,7 @@ _zoxide() {
return 0
;;
zoxide__subcmd__add)
opts="-s -a -h -V --score --alias --help --version <PATHS>..."
opts="-s -h -V --score --help --version <PATHS>..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@ -99,12 +102,32 @@ _zoxide() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--alias)
COMPREPLY=($(compgen -f "${cur}"))
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
zoxide__subcmd__add__subcmd__alias)
opts="-p -h -V --path --help --version <ALIASES>..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
--path)
COMPREPLY=()
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o plusdirs
fi
return 0
;;
-a)
COMPREPLY=($(compgen -f "${cur}"))
-p)
COMPREPLY=()
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o plusdirs
fi
return 0
;;
*)

View File

@ -23,6 +23,7 @@ set edit:completion:arg-completer[zoxide] = {|@words|
cand -V 'Print version'
cand --version 'Print version'
cand add 'Add a new directory or increment its rank'
cand add-alias 'Add aliases for a directory'
cand edit 'Edit the database'
cand import 'Import entries from another application'
cand init 'Generate shell configuration'
@ -32,8 +33,14 @@ set edit:completion:arg-completer[zoxide] = {|@words|
&'zoxide;add'= {
cand -s 'The rank to increment the entry if it exists or initialize it with if it doesn''t'
cand --score 'The rank to increment the entry if it exists or initialize it with if it doesn''t'
cand -a 'a'
cand --alias 'alias'
cand -h 'Print help'
cand --help 'Print help'
cand -V 'Print version'
cand --version 'Print version'
}
&'zoxide;add-alias'= {
cand -p 'p'
cand --path 'path'
cand -h 'Print help'
cand --help 'Print help'
cand -V 'Print version'

View File

@ -27,15 +27,18 @@ end
complete -c zoxide -n "__fish_zoxide_needs_command" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_needs_command" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "add" -d 'Add a new directory or increment its rank'
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "add-alias" -d 'Add aliases for a directory'
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "edit" -d 'Edit the database'
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "import" -d 'Import entries from another application'
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "init" -d 'Generate shell configuration'
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "query" -d 'Search for a directory in the database'
complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "remove" -d 'Remove a directory from the database'
complete -c zoxide -n "__fish_zoxide_using_subcommand add" -s s -l score -d 'The rank to increment the entry if it exists or initialize it with if it doesn\'t' -r
complete -c zoxide -n "__fish_zoxide_using_subcommand add" -s a -l alias -r
complete -c zoxide -n "__fish_zoxide_using_subcommand add" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand add" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand add-alias" -s p -l path -r -f -a "(__fish_complete_directories)"
complete -c zoxide -n "__fish_zoxide_using_subcommand add-alias" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand add-alias" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and not __fish_seen_subcommand_from decrement delete increment reload" -s h -l help -d 'Print help'
complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and not __fish_seen_subcommand_from decrement delete increment reload" -s V -l version -d 'Print version'
complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and not __fish_seen_subcommand_from decrement delete increment reload" -f -a "decrement"

View File

@ -9,12 +9,19 @@ module completions {
# Add a new directory or increment its rank
export extern "zoxide add" [
--score(-s): string # The rank to increment the entry if it exists or initialize it with if it doesn't
--alias(-a): string
--help(-h) # Print help
--version(-V) # Print version
...paths: path
]
# Add aliases for a directory
export extern "zoxide add-alias" [
--path(-p): path
--help(-h) # Print help
--version(-V) # Print version
...aliases: string
]
# Edit the database
export extern "zoxide edit" [
--help(-h) # Print help

View File

@ -15,14 +15,6 @@ const completion: Fig.Spec = {
isOptional: true,
},
},
{
name: ["-a", "--alias"],
isRepeatable: true,
args: {
name: "alias",
isOptional: true,
},
},
{
name: ["-h", "--help"],
description: "Print help",
@ -38,6 +30,32 @@ const completion: Fig.Spec = {
template: "folders",
},
},
{
name: "add-alias",
description: "Add aliases for a directory",
options: [
{
name: ["-p", "--path"],
isRepeatable: true,
args: {
name: "path",
template: "folders",
},
},
{
name: ["-h", "--help"],
description: "Print help",
},
{
name: ["-V", "--version"],
description: "Print version",
},
],
args: {
name: "aliases",
isVariadic: true,
},
},
{
name: "edit",
description: "Edit the database",

View File

@ -18,7 +18,6 @@ impl Run for Add {
let mut db = Database::open()?;
let mut first = true;
for path in &self.paths {
let path =
if config::resolve_symlinks() { util::canonicalize } else { util::resolve_path }(
@ -36,9 +35,7 @@ impl Run for Add {
}
let by = self.score.unwrap_or(1.0);
let alias = if first { self.alias.clone() } else { None };
db.add_update(path, by, now, alias);
first = false;
db.add_update(path, by, now);
}
if db.dirty() {

43
src/cmd/add_alias.rs Normal file
View File

@ -0,0 +1,43 @@
use std::path::Path;
use anyhow::{Result, bail};
use crate::cmd::{AddAlias, Run};
use crate::db::Database;
use crate::{config, util};
impl Run for AddAlias {
fn run(&self) -> Result<()> {
// These characters can't be printed cleanly to a single line, so they can cause
// confusion when writing to stdout.
const EXCLUDE_CHARS: &[char] = &['\n', '\r'];
let exclude_dirs = config::exclude_dirs()?;
let max_age = config::maxage()?;
let now = util::current_time()?;
let mut db = Database::open()?;
let path =
if config::resolve_symlinks() { util::canonicalize } else { util::resolve_path }(
&self.path,
)?;
let path = util::path_to_str(&path)?;
// Ignore path if it contains unsupported characters, or if it's in the exclude
// list.
if path.contains(EXCLUDE_CHARS) || exclude_dirs.iter().any(|glob| glob.matches(path)) {
return Ok(());
}
if !Path::new(path).is_dir() {
bail!("not a directory: {path}");
}
db.add_alias_update(path, self.aliases.iter(), now);
if db.dirty() {
db.age(max_age);
}
db.save()
}
}

View File

@ -42,6 +42,7 @@ https://github.com/ajeetdsouza/zoxide
)]
pub enum Cmd {
Add(Add),
AddAlias(AddAlias),
Edit(Edit),
Import(Import),
Init(Init),
@ -63,9 +64,20 @@ pub struct Add {
/// doesn't
#[clap(short, long)]
pub score: Option<f64>,
}
#[clap(short, long)]
pub alias: Option<String>,
/// Add aliases for a directory
#[derive(Debug, Parser)]
#[clap(
author,
help_template = HelpTemplate,
)]
pub struct AddAlias {
#[clap(num_args = 1.., required = true)]
pub aliases: Vec<String>,
#[clap(short, long, required = true, value_hint = ValueHint::DirPath)]
pub path: PathBuf,
}
/// Edit the database

View File

@ -15,15 +15,11 @@ impl Run for Edit {
match &self.cmd {
Some(cmd) => {
match cmd {
EditCommand::Decrement { path } => {
db.add(path, -1.0, now, Option::<String>::None)
}
EditCommand::Decrement { path } => db.add(path, -1.0, now),
EditCommand::Delete { path } => {
db.remove(path);
}
EditCommand::Increment { path } => {
db.add(path, 1.0, now, Option::<String>::None)
}
EditCommand::Increment { path } => db.add(path, 1.0, now),
EditCommand::Reload => {}
}
db.save()?;

View File

@ -1,4 +1,5 @@
mod add;
mod add_alias;
mod cmd;
mod edit;
mod import;
@ -18,6 +19,7 @@ impl Run for Cmd {
fn run(&self) -> Result<()> {
match self {
Cmd::Add(cmd) => cmd.run(),
Cmd::AddAlias(cmd) => cmd.run(),
Cmd::Edit(cmd) => cmd.run(),
Cmd::Import(cmd) => cmd.run(),
Cmd::Init(cmd) => cmd.run(),

View File

@ -68,33 +68,17 @@ impl Database {
}
/// Increments the rank of a directory, or creates it if it does not exist.
pub fn add(
&mut self,
path: impl AsRef<str> + Into<String>,
by: Rank,
now: Epoch,
alias: Option<impl AsRef<str> + Into<String>>,
) {
pub fn add(&mut self, path: impl AsRef<str> + Into<String>, by: Rank, now: Epoch) {
self.with_dirs_mut(|dirs| match dirs.iter_mut().find(|dir| dir.path == path.as_ref()) {
Some(dir) => {
dir.rank = (dir.rank + by).max(0.0);
if let Some(al) = alias {
dir.aliases.insert(al.into().into());
}
}
None => {
let aliases = if let Some(alias) = alias {
HashSet::from([alias.into().into()])
} else {
HashSet::new()
};
dirs.push(DirV4 {
path: path.into().into(),
rank: by.max(0.0),
last_accessed: now,
aliases,
})
}
None => dirs.push(DirV4 {
path: path.into().into(),
rank: by.max(0.0),
last_accessed: now,
aliases: HashSet::new(),
}),
});
self.with_dirty_mut(|dirty| *dirty = true);
}
@ -103,58 +87,63 @@ impl Database {
/// directory is already in the database, it is expected that the user
/// either does a check before calling this, or calls `dedup()`
/// afterward.
pub fn add_unchecked(
&mut self,
path: impl AsRef<str> + Into<String>,
rank: Rank,
now: Epoch,
alias: Option<impl AsRef<str> + Into<String>>,
) {
pub fn add_unchecked(&mut self, path: impl AsRef<str> + Into<String>, rank: Rank, now: Epoch) {
self.with_dirs_mut(|dirs| {
let aliases = if let Some(alias) = alias {
HashSet::from([alias.into().into()])
} else {
HashSet::new()
};
dirs.push(DirV4 { path: path.into().into(), rank, last_accessed: now, aliases })
dirs.push(DirV4 {
path: path.into().into(),
rank,
last_accessed: now,
aliases: HashSet::new(),
})
});
self.with_dirty_mut(|dirty| *dirty = true);
}
/// Increments the rank and updates the last_accessed of a directory, or
/// creates it if it does not exist.
pub fn add_update(
&mut self,
path: impl AsRef<str> + Into<String>,
by: Rank,
now: Epoch,
alias: Option<impl AsRef<str> + Into<String>>,
) {
pub fn add_update(&mut self, path: impl AsRef<str> + Into<String>, by: Rank, now: Epoch) {
self.with_dirs_mut(|dirs| match dirs.iter_mut().find(|dir| dir.path == path.as_ref()) {
Some(dir) => {
dir.rank = (dir.rank + by).max(0.0);
dir.last_accessed = now;
if let Some(al) = alias {
dir.aliases.insert(al.into().into());
}
}
None => dirs.push(DirV4 {
path: path.into().into(),
rank: by.max(0.0),
last_accessed: now,
aliases: HashSet::new(),
}),
});
self.with_dirty_mut(|dirty| *dirty = true);
}
/// Adds aliases to a directory and updates its last_accessed, or
/// creates it and adds aliases to it if it does not exist.
pub fn add_alias_update(
&mut self,
path: impl AsRef<str> + Into<String>,
aliases: impl Iterator<Item = impl AsRef<str> + Into<String>>,
now: Epoch,
) {
self.with_dirs_mut(|dirs| match dirs.iter_mut().find(|dir| dir.path == path.as_ref()) {
Some(dir) => {
dir.aliases.extend(aliases.map(|alias| alias.into().into()));
dir.last_accessed = now
}
None => {
let aliases = if let Some(alias) = alias {
HashSet::from([alias.into().into()])
} else {
HashSet::new()
};
let mut set = HashSet::new();
set.extend(aliases.map(|alias| alias.into().into()));
dirs.push(DirV4 {
path: path.into().into(),
rank: by.max(0.0),
rank: 0.0,
last_accessed: now,
aliases,
aliases: set,
})
}
});
self.with_dirty_mut(|dirty| *dirty = true);
}
/// Removes the directory with `path` from the store. This does not preserve
/// ordering, but is O(1).
pub fn remove(&mut self, path: impl AsRef<str>) -> bool {
@ -317,8 +306,8 @@ mod tests {
{
let mut db = Database::open_dir(data_dir.path()).unwrap();
db.add(path, 1.0, now, Option::<String>::None);
db.add(path, 1.0, now, Some(String::from("foo")));
db.add(path, 1.0, now);
db.add(path, 1.0, now);
db.save().unwrap();
}
@ -341,7 +330,7 @@ mod tests {
{
let mut db = Database::open_dir(data_dir.path()).unwrap();
db.add(path, 1.0, now, Option::<String>::None);
db.add(path, 1.0, now);
db.save().unwrap();
}

View File

@ -60,7 +60,7 @@ pub(crate) fn run(importer: &impl Importer, db: &mut Database) -> Result<()> {
if exclude_dirs.iter().any(|glob| glob.matches(&dir.path)) {
continue;
}
db.add_unchecked(dir.path, dir.rank, dir.last_accessed, Option::<String>::None);
db.add_unchecked(dir.path, dir.rank, dir.last_accessed);
}
Err(e) => {
let location = match &e.path {