Add POSIX shell support (#43)

Add POSIX shell support

Any users of a shell that adheres to the POSIX standard should now be
supported. Shells that were tested while this feature was in development
include `mrsh`, `dash`, busybox `ash`, and `bash --posix`.

The hook works by defining a `_zoxide_hook` function and adding it to
the shell's `PS1` (causing it to be evaluated every time the prompt is
redrawn).

The PWD hook has been removed, because it is impossible to implement in
a POSIX-compliant and satisfactory way.
This commit is contained in:
Cole Helbling 2020-03-29 14:54:37 -07:00 committed by GitHub
parent a14060335a
commit dc5f965b0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 12 deletions

View File

@ -15,6 +15,7 @@ A cd command that learns your habits
- [zsh](#zsh) - [zsh](#zsh)
- [bash](#bash) - [bash](#bash)
- [fish](#fish) - [fish](#fish)
- [POSIX](#posix)
- [Configuration](#configuration) - [Configuration](#configuration)
- [`init` flags](#init-flags) - [`init` flags](#init-flags)
- [Environment variables](#environment-variables) - [Environment variables](#environment-variables)
@ -89,6 +90,20 @@ Add the following line to your `~/.config/fish/config.fish`:
zoxide init fish | source zoxide init fish | source
``` ```
#### POSIX
Add the following line to your shell's configuration file (or, run it manually):
``` sh
eval "$(zoxide init posix)"
```
NOTE: If you modify your `PS1` at any point, you may need to re-run the above command. This is due
to the fact that we store our hook in `PS1`, in order to be evaluated every time the prompt is
displayed.
NOTE: There is no PWD hook provided for POSIX shells.
## Configuration ## Configuration
### `init` flags ### `init` flags

View File

@ -27,7 +27,7 @@ pub fn main() -> Result<()> {
match opt { match opt {
Zoxide::Add(add) => add.run(&env)?, Zoxide::Add(add) => add.run(&env)?,
Zoxide::Init(init) => init.run(), Zoxide::Init(init) => init.run()?,
Zoxide::Migrate(migrate) => migrate.run(&env)?, Zoxide::Migrate(migrate) => migrate.run(&env)?,
Zoxide::Query(query) => query.run(&env)?, Zoxide::Query(query) => query.run(&env)?,
Zoxide::Remove(remove) => remove.run(&env)?, Zoxide::Remove(remove) => remove.run(&env)?,

View File

@ -1,7 +1,9 @@
use anyhow::{bail, Result};
use clap::arg_enum; use clap::arg_enum;
use std::io::{self, Write};
use structopt::StructOpt; use structopt::StructOpt;
use std::io::{self, Write};
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
#[structopt(about = "Generates shell configuration")] #[structopt(about = "Generates shell configuration")]
pub struct Init { pub struct Init {
@ -25,16 +27,19 @@ pub struct Init {
} }
impl Init { impl Init {
pub fn run(&self) { pub fn run(&self) -> Result<()> {
let config = match self.shell { let config = match self.shell {
Shell::bash => BASH_CONFIG, Shell::bash => BASH_CONFIG,
Shell::fish => FISH_CONFIG, Shell::fish => FISH_CONFIG,
Shell::posix => POSIX_CONFIG,
Shell::zsh => ZSH_CONFIG, Shell::zsh => ZSH_CONFIG,
}; };
let stdout = io::stdout(); let stdout = io::stdout();
let mut handle = stdout.lock(); let mut handle = stdout.lock();
// If any `writeln!` call fails to write to stdout, we assume the user's
// computer is on fire and panic.
writeln!(handle, "{}", config.z).unwrap(); writeln!(handle, "{}", config.z).unwrap();
if !self.no_define_aliases { if !self.no_define_aliases {
writeln!(handle, "{}", config.alias).unwrap(); writeln!(handle, "{}", config.alias).unwrap();
@ -43,8 +48,13 @@ impl Init {
match self.hook { match self.hook {
Hook::none => (), Hook::none => (),
Hook::prompt => writeln!(handle, "{}", config.hook.prompt).unwrap(), Hook::prompt => writeln!(handle, "{}", config.hook.prompt).unwrap(),
Hook::pwd => writeln!(handle, "{}", config.hook.pwd).unwrap(), Hook::pwd => match config.hook.pwd {
}; Some(pwd_hook) => writeln!(handle, "{}", pwd_hook).unwrap(),
None => bail!("PWD hooks are currently unsupported on this shell."),
},
}
Ok(())
} }
} }
@ -54,6 +64,7 @@ arg_enum! {
enum Shell { enum Shell {
bash, bash,
fish, fish,
posix,
zsh, zsh,
} }
} }
@ -73,7 +84,7 @@ const BASH_CONFIG: ShellConfig = ShellConfig {
alias: BASH_ALIAS, alias: BASH_ALIAS,
hook: HookConfig { hook: HookConfig {
prompt: BASH_HOOK_PROMPT, prompt: BASH_HOOK_PROMPT,
pwd: BASH_HOOK_PWD, pwd: Some(BASH_HOOK_PWD),
}, },
}; };
@ -82,7 +93,16 @@ const FISH_CONFIG: ShellConfig = ShellConfig {
alias: FISH_ALIAS, alias: FISH_ALIAS,
hook: HookConfig { hook: HookConfig {
prompt: FISH_HOOK_PROMPT, prompt: FISH_HOOK_PROMPT,
pwd: FISH_HOOK_PWD, pwd: Some(FISH_HOOK_PWD),
},
};
const POSIX_CONFIG: ShellConfig = ShellConfig {
z: POSIX_Z,
alias: POSIX_ALIAS,
hook: HookConfig {
prompt: POSIX_HOOK_PROMPT,
pwd: None,
}, },
}; };
@ -91,7 +111,7 @@ const ZSH_CONFIG: ShellConfig = ShellConfig {
alias: ZSH_ALIAS, alias: ZSH_ALIAS,
hook: HookConfig { hook: HookConfig {
prompt: ZSH_HOOK_PROMPT, prompt: ZSH_HOOK_PROMPT,
pwd: ZSH_HOOK_PWD, pwd: Some(ZSH_HOOK_PWD),
}, },
}; };
@ -103,7 +123,7 @@ struct ShellConfig {
struct HookConfig { struct HookConfig {
prompt: &'static str, prompt: &'static str,
pwd: &'static str, pwd: Option<&'static str>,
} }
const BASH_Z: &str = r#" const BASH_Z: &str = r#"
@ -119,12 +139,17 @@ z() {
if [ "$#" -eq 0 ]; then if [ "$#" -eq 0 ]; then
_z_cd ~ || return "$?" _z_cd ~ || return "$?"
elif [ "$#" -eq 1 ] && [ "$1" = '-' ]; then elif [ "$#" -eq 1 ] && [ "$1" = '-' ]; then
_z_cd ~- || return "$?" if [ -n "$OLDPWD" ]; then
_z_cd "$OLDPWD" || return "$?"
else else
result="$(zoxide query $@)" || return "$?" echo "zoxide: \$OLDPWD is not set"
return 1
fi
else
result="$(zoxide query "$@")" || return "$?"
case "$result" in case "$result" in
"query: "*) "query: "*)
_z_cd "${result:7}" || return "$?" _z_cd "${result#query: }" || return "$?"
;; ;;
*) *)
if [ -n "$result" ]; then if [ -n "$result" ]; then
@ -177,6 +202,8 @@ function z
end end
"#; "#;
const POSIX_Z: &str = BASH_Z;
const ZSH_Z: &str = BASH_Z; const ZSH_Z: &str = BASH_Z;
const BASH_ALIAS: &str = r#" const BASH_ALIAS: &str = r#"
@ -193,6 +220,8 @@ abbr -a zq 'zoxide query'
abbr -a zr 'zoxide remove' abbr -a zr 'zoxide remove'
"#; "#;
const POSIX_ALIAS: &str = BASH_ALIAS;
const ZSH_ALIAS: &str = BASH_ALIAS; const ZSH_ALIAS: &str = BASH_ALIAS;
const BASH_HOOK_PROMPT: &str = r#" const BASH_HOOK_PROMPT: &str = r#"
@ -212,6 +241,17 @@ function _zoxide_hook --on-event fish_prompt
end end
"#; "#;
const POSIX_HOOK_PROMPT: &str = r#"
_zoxide_hook() {
zoxide add > /dev/null
}
case "$PS1" in
*\$\(_zoxide_hook\)*) ;;
*) PS1="\$(_zoxide_hook)${PS1}" ;;
esac
"#;
const ZSH_HOOK_PROMPT: &str = r#" const ZSH_HOOK_PROMPT: &str = r#"
_zoxide_hook() { _zoxide_hook() {
zoxide add zoxide add