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)
- [bash](#bash)
- [fish](#fish)
- [POSIX](#posix)
- [Configuration](#configuration)
- [`init` flags](#init-flags)
- [Environment variables](#environment-variables)
@ -89,6 +90,20 @@ Add the following line to your `~/.config/fish/config.fish`:
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
### `init` flags

View File

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

View File

@ -1,7 +1,9 @@
use anyhow::{bail, Result};
use clap::arg_enum;
use std::io::{self, Write};
use structopt::StructOpt;
use std::io::{self, Write};
#[derive(Debug, StructOpt)]
#[structopt(about = "Generates shell configuration")]
pub struct Init {
@ -25,16 +27,19 @@ pub struct Init {
}
impl Init {
pub fn run(&self) {
pub fn run(&self) -> Result<()> {
let config = match self.shell {
Shell::bash => BASH_CONFIG,
Shell::fish => FISH_CONFIG,
Shell::posix => POSIX_CONFIG,
Shell::zsh => ZSH_CONFIG,
};
let stdout = io::stdout();
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();
if !self.no_define_aliases {
writeln!(handle, "{}", config.alias).unwrap();
@ -43,8 +48,13 @@ impl Init {
match self.hook {
Hook::none => (),
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 {
bash,
fish,
posix,
zsh,
}
}
@ -73,7 +84,7 @@ const BASH_CONFIG: ShellConfig = ShellConfig {
alias: BASH_ALIAS,
hook: HookConfig {
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,
hook: HookConfig {
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,
hook: HookConfig {
prompt: ZSH_HOOK_PROMPT,
pwd: ZSH_HOOK_PWD,
pwd: Some(ZSH_HOOK_PWD),
},
};
@ -103,7 +123,7 @@ struct ShellConfig {
struct HookConfig {
prompt: &'static str,
pwd: &'static str,
pwd: Option<&'static str>,
}
const BASH_Z: &str = r#"
@ -119,12 +139,17 @@ z() {
if [ "$#" -eq 0 ]; then
_z_cd ~ || return "$?"
elif [ "$#" -eq 1 ] && [ "$1" = '-' ]; then
_z_cd ~- || return "$?"
if [ -n "$OLDPWD" ]; then
_z_cd "$OLDPWD" || return "$?"
else
result="$(zoxide query $@)" || return "$?"
echo "zoxide: \$OLDPWD is not set"
return 1
fi
else
result="$(zoxide query "$@")" || return "$?"
case "$result" in
"query: "*)
_z_cd "${result:7}" || return "$?"
_z_cd "${result#query: }" || return "$?"
;;
*)
if [ -n "$result" ]; then
@ -177,6 +202,8 @@ function z
end
"#;
const POSIX_Z: &str = BASH_Z;
const ZSH_Z: &str = BASH_Z;
const BASH_ALIAS: &str = r#"
@ -193,6 +220,8 @@ abbr -a zq 'zoxide query'
abbr -a zr 'zoxide remove'
"#;
const POSIX_ALIAS: &str = BASH_ALIAS;
const ZSH_ALIAS: &str = BASH_ALIAS;
const BASH_HOOK_PROMPT: &str = r#"
@ -212,6 +241,17 @@ function _zoxide_hook --on-event fish_prompt
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#"
_zoxide_hook() {
zoxide add