env_hooks/shells/
zsh.rs

1use std::collections::HashSet;
2
3use bstr::{B, BString, ByteSlice};
4use shell_quote::Zsh;
5
6use crate::EnvVarsState;
7
8const ZSH_HOOK: &str = r#"
9    _{{.HookPrefix}}_hook() {
10        vars="$({{.ExportCommand}})"
11        trap -- '' SIGINT
12        eval "$vars"
13        trap - SIGINT
14    }
15    typeset -ag precmd_functions
16    if (( ! ${precmd_functions[(I)_{{.HookPrefix}}_hook]} )); then
17        precmd_functions=(_{{.HookPrefix}}_hook $precmd_functions)
18    fi
19    typeset -ag chpwd_functions
20    if (( ! ${chpwd_functions[(I)_{{.HookPrefix}}_hook]} )); then
21        chpwd_functions=(_{{.HookPrefix}}_hook $chpwd_functions)
22    fi
23"#;
24
25pub fn hook(hook_prefix: impl AsRef<[u8]>, export_command: impl AsRef<[u8]>) -> BString {
26    BString::from(ZSH_HOOK)
27        .replace("{{.HookPrefix}}", hook_prefix)
28        .replace("{{.ExportCommand}}", export_command)
29        .into()
30}
31
32pub fn export(
33    env_vars_state: EnvVarsState,
34    _semicolon_delimited_env_vars: Option<&HashSet<String>>,
35) -> BString {
36    let exports = env_vars_state
37        .iter()
38        .map(|(key, state)| {
39            if let Some(value) = state {
40                export_var(key, value)
41            } else {
42                unset_var(key)
43            }
44        })
45        .collect::<Vec<_>>();
46    bstr::join("\n", exports).into()
47}
48
49fn export_var(key: &str, value: &str) -> BString {
50    let script = bstr::join(" ", [B("export"), &Zsh::quote_vec(key)]);
51    let value = Zsh::quote_vec(value);
52    bstr::concat([&bstr::join("=", [script, value]), B(";")]).into()
53}
54
55fn unset_var(key: &str) -> BString {
56    bstr::concat([&bstr::join(" ", [B("unset"), &Zsh::quote_vec(key)]), B(";")]).into()
57}