1use std::collections::HashSet;
2
3use bstr::{B, BString, ByteSlice};
4use shell_quote::Fish;
5
6use crate::EnvVarsState;
7
8const FISH_HOOK: &str = r#"
9 function __{{.HookPrefix}}_export_eval --on-event fish_prompt;
10 {{.ExportCommand}} | source;
11
12 if test "${{.HookPrefix}}_fish_mode" != "disable_arrow";
13 function __{{.HookPrefix}}_cd_hook --on-variable PWD;
14 if test "${{.HookPrefix}}_fish_mode" = "eval_after_arrow";
15 set -g __{{.HookPrefix}}_export_again 0;
16 else;
17 {{.ExportCommand}} | source;
18 end;
19 end;
20 end;
21 end;
22
23 function __{{.HookPrefix}}_export_eval_2 --on-event fish_preexec;
24 if set -q __{{.HookPrefix}}_export_again;
25 set -e __{{.HookPrefix}}_export_again;
26 {{.ExportCommand}} | source;
27 echo;
28 end;
29
30 functions --erase __{{.HookPrefix}}_cd_hook;
31 end;
32"#;
33
34pub fn hook(hook_prefix: impl AsRef<[u8]>, export_command: impl AsRef<[u8]>) -> BString {
35 BString::from(FISH_HOOK)
36 .replace("{{.HookPrefix}}", hook_prefix)
37 .replace("{{.ExportCommand}}", export_command)
38 .into()
39}
40
41pub fn export(
42 env_vars_state: EnvVarsState,
43 semicolon_delimited_env_vars: Option<&HashSet<String>>,
44) -> BString {
45 let exports = env_vars_state
46 .iter()
47 .map(|(key, state)| {
48 if let Some(value) = state {
49 export_var(key, value, semicolon_delimited_env_vars)
50 } else {
51 unset_var(key)
52 }
53 })
54 .collect::<Vec<_>>();
55 bstr::join("\n", exports).into()
56}
57
58fn export_var(
59 key: &str,
60 value: &str,
61 semicolon_delimited_env_vars: Option<&HashSet<String>>,
62) -> BString {
63 let script = bstr::join(" ", [B("set -x -g"), &Fish::quote_vec(key)]);
64 let value = if let Some(sdev) = semicolon_delimited_env_vars
65 && sdev.contains(key)
66 {
67 let value_parts = value.split(':').map(Fish::quote_vec).collect::<Vec<_>>();
68 bstr::join(" ", value_parts)
69 } else {
70 Fish::quote_vec(value)
71 };
72 bstr::concat([&bstr::join(" ", [script, value]), B(";")]).into()
73}
74
75fn unset_var(key: &str) -> BString {
76 bstr::concat([
77 &bstr::join(" ", [B("set -e -g"), &Fish::quote_vec(key)]),
78 B(";"),
79 ])
80 .into()
81}