diff --git a/Cargo.lock b/Cargo.lock index c947d55..031bc34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,6 +166,15 @@ dependencies = [ "syn", ] +[[package]] +name = "clap_generate" +version = "3.0.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf420f8b687b628d2915ccfd43a660c437a170432e3fbcb66944e8717a0d68f" +dependencies = [ + "clap", +] + [[package]] name = "difference" version = "2.0.0" @@ -741,6 +750,7 @@ dependencies = [ "assert_cmd", "bincode", "clap", + "clap_generate", "dirs-next", "dunce", "glob", diff --git a/Cargo.toml b/Cargo.toml index 198640b..1d9dee5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,10 @@ assert_cmd = "1.0.1" once_cell = "1.4.1" seq-macro = "0.2.1" +[build-dependencies] +clap = "3.0.0-beta.2" +clap_generate = "3.0.0-beta.2" + [features] default = [] # Adds tests for code generated by `zoxide init`. diff --git a/build.rs b/build.rs index 2537f3a..5441331 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,23 @@ +use clap::IntoApp; +use clap_generate::{generate_to, generators::*}; + use std::env; use std::process::Command; +include!("src/app.rs"); + +fn completions() { + let mut app = Cli::into_app(); + let bin_name = env!("CARGO_PKG_NAME"); + let out_dir = "contrib/completions"; + + generate_to::(&mut app, bin_name, out_dir); + generate_to::(&mut app, bin_name, out_dir); + generate_to::(&mut app, bin_name, out_dir); + generate_to::(&mut app, bin_name, out_dir); + generate_to::(&mut app, bin_name, out_dir); +} + fn git_version() -> Option { // Packages releases of zoxide almost always use the source tarball // provided by GitHub, which does not include the `.git` folder. Since this @@ -21,4 +38,5 @@ fn crate_version() -> String { fn main() { let version = git_version().unwrap_or_else(crate_version); println!("cargo:rustc-env=ZOXIDE_VERSION={}", version); + completions(); } diff --git a/contrib/completions/_zoxide b/contrib/completions/_zoxide new file mode 100644 index 0000000..1d56a50 --- /dev/null +++ b/contrib/completions/_zoxide @@ -0,0 +1,132 @@ +#compdef zoxide + +autoload -U is-at-least + +_zoxide() { + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext="$curcontext" state line + _arguments "${_arguments_options[@]}" \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +":: :_zoxide_commands" \ +"*::: :->zoxide" \ +&& ret=0 + case $state in + (zoxide) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:zoxide-command-$line[1]:" + case $line[1] in + (add) +_arguments "${_arguments_options[@]}" \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +':path:' \ +&& ret=0 +;; +(import) +_arguments "${_arguments_options[@]}" \ +'--from=[Application to import from]: :(autojump z)' \ +'--merge[Merge into existing database]' \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +':path:' \ +&& ret=0 +;; +(init) +_arguments "${_arguments_options[@]}" \ +'--cmd=[Renames the '\''z'\'' command and corresponding aliases]' \ +'--hook=[Chooses event upon which an entry is added to the database]: :(none prompt pwd)' \ +'--no-aliases[Prevents zoxide from defining any commands]' \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +':shell:(bash elvish fish nushell posix powershell xonsh zsh)' \ +&& ret=0 +;; +(query) +_arguments "${_arguments_options[@]}" \ +'--exclude=[Exclude a path from results]' \ +'(-l --list)-i[Use interactive selection]' \ +'(-l --list)--interactive[Use interactive selection]' \ +'(-i --interactive)-l[List all matching directories]' \ +'(-i --interactive)--list[List all matching directories]' \ +'-s[Print score with results]' \ +'--score[Print score with results]' \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'*::keywords:' \ +&& ret=0 +;; +(remove) +_arguments "${_arguments_options[@]}" \ +'()*-i+[]' \ +'()*--interactive=[]' \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'::path:' \ +&& ret=0 +;; + esac + ;; +esac +} + +(( $+functions[_zoxide_commands] )) || +_zoxide_commands() { + local commands; commands=( + "add:Add a new directory or increment its rank" \ +"import:Import entries from another application" \ +"init:Generate shell configuration" \ +"query:Search for a directory in the database" \ +"remove:Remove a directory from the database" \ + ) + _describe -t commands 'zoxide commands' commands "$@" +} +(( $+functions[_zoxide__add_commands] )) || +_zoxide__add_commands() { + local commands; commands=( + + ) + _describe -t commands 'zoxide add commands' commands "$@" +} +(( $+functions[_zoxide__import_commands] )) || +_zoxide__import_commands() { + local commands; commands=( + + ) + _describe -t commands 'zoxide import commands' commands "$@" +} +(( $+functions[_zoxide__init_commands] )) || +_zoxide__init_commands() { + local commands; commands=( + + ) + _describe -t commands 'zoxide init commands' commands "$@" +} +(( $+functions[_zoxide__query_commands] )) || +_zoxide__query_commands() { + local commands; commands=( + + ) + _describe -t commands 'zoxide query commands' commands "$@" +} +(( $+functions[_zoxide__remove_commands] )) || +_zoxide__remove_commands() { + local commands; commands=( + + ) + _describe -t commands 'zoxide remove commands' commands "$@" +} + +_zoxide "$@" \ No newline at end of file diff --git a/contrib/completions/_zoxide.ps1 b/contrib/completions/_zoxide.ps1 new file mode 100644 index 0000000..1392f3b --- /dev/null +++ b/contrib/completions/_zoxide.ps1 @@ -0,0 +1,77 @@ + +using namespace System.Management.Automation +using namespace System.Management.Automation.Language + +Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + + $commandElements = $commandAst.CommandElements + $command = @( + 'zoxide' + for ($i = 1; $i -lt $commandElements.Count; $i++) { + $element = $commandElements[$i] + if ($element -isnot [StringConstantExpressionAst] -or + $element.StringConstantType -ne [StringConstantType]::BareWord -or + $element.Value.StartsWith('-')) { + break + } + $element.Value + }) -join ';' + + $completions = @(switch ($command) { + 'zoxide' { + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('add', 'add', [CompletionResultType]::ParameterValue, 'Add a new directory or increment its rank') + [CompletionResult]::new('import', 'import', [CompletionResultType]::ParameterValue, 'Import entries from another application') + [CompletionResult]::new('init', 'init', [CompletionResultType]::ParameterValue, 'Generate shell configuration') + [CompletionResult]::new('query', 'query', [CompletionResultType]::ParameterValue, 'Search for a directory in the database') + [CompletionResult]::new('remove', 'remove', [CompletionResultType]::ParameterValue, 'Remove a directory from the database') + break + } + 'zoxide;add' { + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + break + } + 'zoxide;import' { + [CompletionResult]::new('--from', 'from', [CompletionResultType]::ParameterName, 'Application to import from') + [CompletionResult]::new('--merge', 'merge', [CompletionResultType]::ParameterName, 'Merge into existing database') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + break + } + 'zoxide;init' { + [CompletionResult]::new('--cmd', 'cmd', [CompletionResultType]::ParameterName, 'Renames the ''z'' command and corresponding aliases') + [CompletionResult]::new('--hook', 'hook', [CompletionResultType]::ParameterName, 'Chooses event upon which an entry is added to the database') + [CompletionResult]::new('--no-aliases', 'no-aliases', [CompletionResultType]::ParameterName, 'Prevents zoxide from defining any commands') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + break + } + 'zoxide;query' { + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'Exclude a path from results') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'Use interactive selection') + [CompletionResult]::new('--interactive', 'interactive', [CompletionResultType]::ParameterName, 'Use interactive selection') + [CompletionResult]::new('-l', 'l', [CompletionResultType]::ParameterName, 'List all matching directories') + [CompletionResult]::new('--list', 'list', [CompletionResultType]::ParameterName, 'List all matching directories') + [CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Print score with results') + [CompletionResult]::new('--score', 'score', [CompletionResultType]::ParameterName, 'Print score with results') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + break + } + 'zoxide;remove' { + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'i') + [CompletionResult]::new('--interactive', 'interactive', [CompletionResultType]::ParameterName, 'interactive') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + break + } + }) + + $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | + Sort-Object -Property ListItemText +} diff --git a/contrib/completions/zoxide.bash b/contrib/completions/zoxide.bash new file mode 100644 index 0000000..5bfc32a --- /dev/null +++ b/contrib/completions/zoxide.bash @@ -0,0 +1,155 @@ +_zoxide() { + local i cur prev opts cmds + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + cmd="" + opts="" + + for i in ${COMP_WORDS[@]} + do + case "${i}" in + zoxide) + cmd="zoxide" + ;; + + add) + cmd+="__add" + ;; + import) + cmd+="__import" + ;; + init) + cmd+="__init" + ;; + query) + cmd+="__query" + ;; + remove) + cmd+="__remove" + ;; + *) + ;; + esac + done + + case "${cmd}" in + zoxide) + opts=" -h -V --help --version add import init query remove" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + + zoxide__add) + opts=" -h --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + zoxide__import) + opts=" -h --from --merge --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + --from) + COMPREPLY=($(compgen -W "autojump z" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + zoxide__init) + opts=" -h --no-aliases --cmd --hook --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + --cmd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --hook) + COMPREPLY=($(compgen -W "none prompt pwd" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + zoxide__query) + opts=" -i -l -s -h --interactive --list --score --exclude --help ... " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + zoxide__remove) + opts=" -i -h --interactive --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + --interactive) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -i) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + esac +} + +complete -F _zoxide -o bashdefault -o default zoxide diff --git a/contrib/completions/zoxide.elv b/contrib/completions/zoxide.elv new file mode 100644 index 0000000..16ff14f --- /dev/null +++ b/contrib/completions/zoxide.elv @@ -0,0 +1,64 @@ + +edit:completion:arg-completer[zoxide] = [@words]{ + fn spaces [n]{ + repeat $n ' ' | joins '' + } + fn cand [text desc]{ + edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc + } + command = 'zoxide' + for word $words[1:-1] { + if (has-prefix $word '-') { + break + } + command = $command';'$word + } + completions = [ + &'zoxide'= { + cand -h 'Prints help information' + cand --help 'Prints help information' + cand -V 'Prints version information' + cand --version 'Prints version information' + cand add 'Add a new directory or increment its rank' + cand import 'Import entries from another application' + cand init 'Generate shell configuration' + cand query 'Search for a directory in the database' + cand remove 'Remove a directory from the database' + } + &'zoxide;add'= { + cand -h 'Prints help information' + cand --help 'Prints help information' + } + &'zoxide;import'= { + cand --from 'Application to import from' + cand --merge 'Merge into existing database' + cand -h 'Prints help information' + cand --help 'Prints help information' + } + &'zoxide;init'= { + cand --cmd 'Renames the ''z'' command and corresponding aliases' + cand --hook 'Chooses event upon which an entry is added to the database' + cand --no-aliases 'Prevents zoxide from defining any commands' + cand -h 'Prints help information' + cand --help 'Prints help information' + } + &'zoxide;query'= { + cand --exclude 'Exclude a path from results' + cand -i 'Use interactive selection' + cand --interactive 'Use interactive selection' + cand -l 'List all matching directories' + cand --list 'List all matching directories' + cand -s 'Print score with results' + cand --score 'Print score with results' + cand -h 'Prints help information' + cand --help 'Prints help information' + } + &'zoxide;remove'= { + cand -i 'i' + cand --interactive 'interactive' + cand -h 'Prints help information' + cand --help 'Prints help information' + } + ] + $completions[$command] +} diff --git a/contrib/completions/zoxide.fish b/contrib/completions/zoxide.fish new file mode 100644 index 0000000..450b73f --- /dev/null +++ b/contrib/completions/zoxide.fish @@ -0,0 +1,27 @@ +complete -c zoxide -n "__fish_use_subcommand" -s h -l help -d 'Prints help information' +complete -c zoxide -n "__fish_use_subcommand" -s V -l version -d 'Prints version information' +complete -c zoxide -n "__fish_use_subcommand" -f -a "add" -d 'Add a new directory or increment its rank' +complete -c zoxide -n "__fish_use_subcommand" -f -a "import" -d 'Import entries from another application' +complete -c zoxide -n "__fish_use_subcommand" -f -a "init" -d 'Generate shell configuration' +complete -c zoxide -n "__fish_use_subcommand" -f -a "query" -d 'Search for a directory in the database' +complete -c zoxide -n "__fish_use_subcommand" -f -a "remove" -d 'Remove a directory from the database' +complete -c zoxide -n "__fish_seen_subcommand_from add" -r +complete -c zoxide -n "__fish_seen_subcommand_from add" -s h -l help -d 'Prints help information' +complete -c zoxide -n "__fish_seen_subcommand_from import" -r +complete -c zoxide -n "__fish_seen_subcommand_from import" -l from -d 'Application to import from' -r -f -a "autojump z" +complete -c zoxide -n "__fish_seen_subcommand_from import" -l merge -d 'Merge into existing database' +complete -c zoxide -n "__fish_seen_subcommand_from import" -s h -l help -d 'Prints help information' +complete -c zoxide -n "__fish_seen_subcommand_from init" -r -f -a "bash elvish fish nushell posix powershell xonsh zsh" +complete -c zoxide -n "__fish_seen_subcommand_from init" -l cmd -d 'Renames the \'z\' command and corresponding aliases' -r +complete -c zoxide -n "__fish_seen_subcommand_from init" -l hook -d 'Chooses event upon which an entry is added to the database' -r -f -a "none prompt pwd" +complete -c zoxide -n "__fish_seen_subcommand_from init" -l no-aliases -d 'Prevents zoxide from defining any commands' +complete -c zoxide -n "__fish_seen_subcommand_from init" -s h -l help -d 'Prints help information' +complete -c zoxide -n "__fish_seen_subcommand_from query" -r +complete -c zoxide -n "__fish_seen_subcommand_from query" -l exclude -d 'Exclude a path from results' -r +complete -c zoxide -n "__fish_seen_subcommand_from query" -s i -l interactive -d 'Use interactive selection' +complete -c zoxide -n "__fish_seen_subcommand_from query" -s l -l list -d 'List all matching directories' +complete -c zoxide -n "__fish_seen_subcommand_from query" -s s -l score -d 'Print score with results' +complete -c zoxide -n "__fish_seen_subcommand_from query" -s h -l help -d 'Prints help information' +complete -c zoxide -n "__fish_seen_subcommand_from remove" -s i -l interactive -r +complete -c zoxide -n "__fish_seen_subcommand_from remove" -r +complete -c zoxide -n "__fish_seen_subcommand_from remove" -s h -l help -d 'Prints help information' diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..96c552f --- /dev/null +++ b/src/app.rs @@ -0,0 +1,130 @@ +use clap::{AppSettings, ArgEnum, Clap}; + +use std::path::PathBuf; + +const ENV_HELP: &str = "ENVIRONMENT VARIABLES: + _ZO_DATA_DIR Path for zoxide data files + _ZO_ECHO Prints the matched directory before navigating to it when set to 1 + _ZO_EXCLUDE_DIRS List of directory globs to be excluded + _ZO_FZF_OPTS Custom flags to pass to fzf + _ZO_MAXAGE Maximum total age after which entries start getting deleted + _ZO_RESOLVE_SYMLINKS Resolve symlinks when storing paths"; + +#[derive(Debug, Clap)] +#[clap( + bin_name = env!("CARGO_PKG_NAME"), + about, + author, + after_help = ENV_HELP, + global_setting(AppSettings::ColoredHelp), + global_setting(AppSettings::DisableHelpSubcommand), + global_setting(AppSettings::GlobalVersion), + global_setting(AppSettings::VersionlessSubcommands), + version = option_env!("ZOXIDE_VERSION").unwrap_or("") +)] +pub enum Cli { + Add(Add), + Import(Import), + Init(Init), + Query(Query), + Remove(Remove), +} + +/// Add a new directory or increment its rank +#[derive(Clap, Debug)] +pub struct Add { + pub path: PathBuf, +} + +/// Import entries from another application +#[derive(Clap, Debug)] +pub struct Import { + pub path: PathBuf, + + /// Application to import from + #[clap(arg_enum, long)] + pub from: From, + + /// Merge into existing database + #[clap(long)] + pub merge: bool, +} + +#[derive(ArgEnum, Debug)] +pub enum From { + Autojump, + Z, +} + +/// Generate shell configuration +#[derive(Clap, Debug)] +pub struct Init { + #[clap(arg_enum)] + pub shell: Shell, + + /// Prevents zoxide from defining any commands + #[clap(long)] + pub no_aliases: bool, + + /// Renames the 'z' command and corresponding aliases + #[clap(long, default_value = "z")] + pub cmd: String, + + /// Chooses event upon which an entry is added to the database + #[clap(arg_enum, long, default_value = "pwd")] + pub hook: Hook, +} + +#[derive(ArgEnum, Debug)] +pub enum Shell { + Bash, + Elvish, + Fish, + Nushell, + Posix, + Powershell, + Xonsh, + Zsh, +} + +#[derive(ArgEnum, Clone, Copy, Debug, Eq, PartialEq)] +pub enum Hook { + None, + Prompt, + Pwd, +} + +/// Search for a directory in the database +#[derive(Clap, Debug)] +pub struct Query { + pub keywords: Vec, + + /// Use interactive selection + #[clap(long, short, conflicts_with = "list")] + pub interactive: bool, + + /// List all matching directories + #[clap(long, short, conflicts_with = "interactive")] + pub list: bool, + + /// Print score with results + #[clap(long, short)] + pub score: bool, + + /// Exclude a path from results + #[clap(long, hidden = true)] + pub exclude: Option, +} + +/// Remove a directory from the database +#[derive(Clap, Debug)] +pub struct Remove { + // Use interactive selection + #[clap(conflicts_with = "path", long, short, value_name = "keywords")] + pub interactive: Option>, + #[clap( + conflicts_with = "interactive", + required_unless_present = "interactive" + )] + pub path: Option, +} diff --git a/src/cmd/add.rs b/src/cmd/add.rs index 1b34cc3..2edd318 100644 --- a/src/cmd/add.rs +++ b/src/cmd/add.rs @@ -1,20 +1,12 @@ -use super::Cmd; +use super::Run; +use crate::app::Add; use crate::config; use crate::db::DatabaseFile; use crate::util; use anyhow::{bail, Result}; -use clap::Clap; -use std::path::PathBuf; - -/// Add a new directory or increment its rank -#[derive(Clap, Debug)] -pub struct Add { - path: PathBuf, -} - -impl Cmd for Add { +impl Run for Add { fn run(&self) -> Result<()> { let path = if config::zo_resolve_symlinks() { util::canonicalize(&self.path) diff --git a/src/cmd/import.rs b/src/cmd/import.rs index 959db74..53ae0e8 100644 --- a/src/cmd/import.rs +++ b/src/cmd/import.rs @@ -1,29 +1,13 @@ -use super::Cmd; +use super::Run; +use crate::app::{From, Import}; use crate::config; use crate::import::{Autojump, Import as _, Z}; use crate::util; use crate::db::DatabaseFile; use anyhow::{bail, Result}; -use clap::{ArgEnum, Clap}; -use std::path::PathBuf; - -/// Import entries from another application -#[derive(Clap, Debug)] -pub struct Import { - path: PathBuf, - - /// Application to import from - #[clap(arg_enum, long)] - from: From, - - /// Merge into existing database - #[clap(long)] - merge: bool, -} - -impl Cmd for Import { +impl Run for Import { fn run(&self) -> Result<()> { let data_dir = config::zo_data_dir()?; @@ -44,9 +28,3 @@ impl Cmd for Import { } } } - -#[derive(ArgEnum, Debug)] -enum From { - Autojump, - Z, -} diff --git a/src/cmd/init.rs b/src/cmd/init.rs index 63ea435..1bd39e9 100644 --- a/src/cmd/init.rs +++ b/src/cmd/init.rs @@ -1,34 +1,15 @@ -use super::Cmd; +use super::Run; +use crate::app::{Init, Shell}; use crate::config; use crate::error::WriteErrorHandler; -use crate::shell::{self, Hook, Opts}; +use crate::shell::{self, Opts}; use anyhow::{Context, Result}; use askama::Template; -use clap::{ArgEnum, Clap}; use std::io::{self, Write}; -/// Generate shell configuration -#[derive(Clap, Debug)] -pub struct Init { - #[clap(arg_enum)] - shell: Shell, - - /// Prevents zoxide from defining any commands - #[clap(long)] - no_aliases: bool, - - /// Renames the 'z' command and corresponding aliases - #[clap(long, default_value = "z")] - cmd: String, - - /// Chooses event upon which an entry is added to the database - #[clap(arg_enum, long, default_value = "pwd")] - hook: Hook, -} - -impl Cmd for Init { +impl Run for Init { fn run(&self) -> Result<()> { let cmd = if self.no_aliases { None @@ -60,15 +41,3 @@ impl Cmd for Init { writeln!(io::stdout(), "{}", source).wrap_write("stdout") } } - -#[derive(ArgEnum, Debug)] -enum Shell { - Bash, - Elvish, - Fish, - Nushell, - Posix, - Powershell, - Xonsh, - Zsh, -} diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 3b24f73..c52b21d 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -4,53 +4,22 @@ mod init; mod query; mod remove; +use crate::app::Cli; + use anyhow::Result; -use clap::{AppSettings, Clap}; -pub use add::Add; -pub use import::Import; -pub use init::Init; -pub use query::Query; -pub use remove::Remove; - -const ENV_HELP: &str = "ENVIRONMENT VARIABLES: - _ZO_DATA_DIR Path for zoxide data files - _ZO_ECHO Prints the matched directory before navigating to it when set to 1 - _ZO_EXCLUDE_DIRS List of directory globs to be excluded - _ZO_FZF_OPTS Custom flags to pass to fzf - _ZO_MAXAGE Maximum total age after which entries start getting deleted - _ZO_RESOLVE_SYMLINKS Resolve symlinks when storing paths"; - -pub trait Cmd { +pub trait Run { fn run(&self) -> Result<()>; } -#[derive(Debug, Clap)] -#[clap( - about, - author, - after_help = ENV_HELP, - global_setting(AppSettings::ColoredHelp), - global_setting(AppSettings::DisableHelpSubcommand), - global_setting(AppSettings::GlobalVersion), - global_setting(AppSettings::VersionlessSubcommands), - version = env!("ZOXIDE_VERSION"))] -pub enum App { - Add(Add), - Import(Import), - Init(Init), - Query(Query), - Remove(Remove), -} - -impl Cmd for App { +impl Run for Cli { fn run(&self) -> Result<()> { match self { - App::Add(cmd) => cmd.run(), - App::Import(cmd) => cmd.run(), - App::Init(cmd) => cmd.run(), - App::Query(cmd) => cmd.run(), - App::Remove(cmd) => cmd.run(), + Cli::Add(cmd) => cmd.run(), + Cli::Import(cmd) => cmd.run(), + Cli::Init(cmd) => cmd.run(), + Cli::Query(cmd) => cmd.run(), + Cli::Remove(cmd) => cmd.run(), } } } diff --git a/src/cmd/query.rs b/src/cmd/query.rs index bfbcea6..7e8bd33 100644 --- a/src/cmd/query.rs +++ b/src/cmd/query.rs @@ -1,4 +1,5 @@ -use super::Cmd; +use super::Run; +use crate::app::Query; use crate::config; use crate::db::{self, DatabaseFile}; use crate::error::WriteErrorHandler; @@ -6,33 +7,10 @@ use crate::fzf::Fzf; use crate::util; use anyhow::{Context, Result}; -use clap::Clap; use std::io::{self, BufWriter, Write}; -/// Search for a directory in the database -#[derive(Clap, Debug)] -pub struct Query { - keywords: Vec, - - /// Use interactive selection - #[clap(long, short, conflicts_with = "list")] - interactive: bool, - - /// List all matching directories - #[clap(long, short, conflicts_with = "interactive")] - list: bool, - - /// Print score with results - #[clap(long, short)] - score: bool, - - /// Exclude a path from results - #[clap(long, hidden = true)] - exclude: Option, -} - -impl Cmd for Query { +impl Run for Query { fn run(&self) -> Result<()> { let data_dir = config::zo_data_dir()?; let mut db = DatabaseFile::new(data_dir); diff --git a/src/cmd/remove.rs b/src/cmd/remove.rs index 5b03866..a912385 100644 --- a/src/cmd/remove.rs +++ b/src/cmd/remove.rs @@ -1,4 +1,5 @@ -use super::Cmd; +use super::Run; +use crate::app::Remove; use crate::config; use crate::db::{DatabaseFile, Query}; use crate::error::WriteErrorHandler; @@ -6,24 +7,10 @@ use crate::fzf::Fzf; use crate::util; use anyhow::{bail, Result}; -use clap::Clap; use std::io::Write; -/// Remove a directory from the database -#[derive(Clap, Debug)] -pub struct Remove { - // Use interactive selection - #[clap(conflicts_with = "path", long, short, value_name = "keywords")] - interactive: Option>, - #[clap( - conflicts_with = "interactive", - required_unless_present = "interactive" - )] - path: Option, -} - -impl Cmd for Remove { +impl Run for Remove { fn run(&self) -> Result<()> { let data_dir = config::zo_data_dir()?; let mut db = DatabaseFile::new(data_dir); diff --git a/src/main.rs b/src/main.rs index 5fe4580..967b33b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod app; mod cmd; mod config; mod db; @@ -7,7 +8,8 @@ mod import; mod shell; mod util; -use crate::cmd::{App, Cmd}; +use crate::app::Cli; +use crate::cmd::Run; use crate::error::SilentExit; use clap::Clap; @@ -21,7 +23,7 @@ pub fn main() { env::remove_var("RUST_LIB_BACKTRACE"); env::remove_var("RUST_BACKTRACE"); - if let Err(e) = App::parse().run() { + if let Err(e) = Cli::parse().run() { match e.downcast::() { Ok(SilentExit { code }) => process::exit(code), Err(e) => { diff --git a/src/shell.rs b/src/shell.rs index 0aad47d..2dbfd47 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -1,9 +1,9 @@ -use clap::ArgEnum; +use crate::app::Hook; #[derive(Debug, Eq, PartialEq)] pub struct Opts<'a> { pub cmd: Option<&'a str>, - pub hook: Hook, + pub(crate) hook: Hook, pub echo: bool, pub resolve_symlinks: bool, } @@ -32,13 +32,6 @@ make_template!(Powershell, "powershell.txt"); make_template!(Xonsh, "xonsh.txt"); make_template!(Zsh, "zsh.txt"); -#[derive(ArgEnum, Clone, Copy, Debug, Eq, PartialEq)] -pub enum Hook { - None, - Prompt, - Pwd, -} - #[cfg(feature = "shell_tests")] #[cfg(test)] mod tests {