use super::{ActivateOptions, Shell};
use std::fmt;
pub struct Nushell;
impl Shell for Nushell {
fn activate(&self, opts: ActivateOptions) -> String {
let mut out = String::new();
let exe = opts.exe.to_string_lossy().replace('\\', "/");
out.push_str("$env.FNOX_SHELL = \"nu\"\n");
out.push_str(
r#"
def --env _fnox_apply [json: string] {
let changes = ($json | from json)
if "set" in $changes and ($changes.set | is-not-empty) {
$changes.set | load-env
}
if "unset" in $changes and ($changes.unset | is-not-empty) {
for $var in $changes.unset {
hide-env -i $var
}
}
}
"#,
);
out.push_str(&format!(
r#"
def --env --wrapped fnox [...rest] {{
let command = ($rest | first | default "")
match $command {{
"deactivate" => {{
let result = (do -i {{ ^"{exe}" $command ...($rest | skip 1) }} | complete)
if ($result.stderr | str trim | is-not-empty) {{
print -e $result.stderr
}}
if $result.exit_code == 0 and ($result.stdout | str trim | is-not-empty) {{
_fnox_apply $result.stdout
}}
if $command == "deactivate" {{
$env.config = ($env.config | upsert hooks.pre_prompt ($env.config.hooks.pre_prompt? | default [] | where {{ ($in | describe) != "closure" or (view source $in) !~ "_fnox_hook" }}))
hide-env -i FNOX_SHELL
hide-env -i __FNOX_SESSION
}}
}}
_ => {{ ^"{exe}" ...$rest }}
}}
}}
"#,
));
if !opts.no_hook_env {
out.push_str(&format!(
r#"
def --env _fnox_hook [] {{
let result = (do -i {{ ^"{exe}" hook-env -s nu }} | complete)
if ($result.stderr | str trim | is-not-empty) {{
print -e $result.stderr
}}
if $result.exit_code == 0 and ($result.stdout | str trim | is-not-empty) {{
_fnox_apply $result.stdout
}}
}}
"#,
));
out.push_str(
r#"
$env.config = ($env.config | upsert hooks.pre_prompt ($env.config.hooks.pre_prompt? | default [] | append {|| _fnox_hook }))
"#,
);
out.push_str("_fnox_hook\n");
}
out
}
fn deactivate(&self) -> String {
unimplemented!("Nushell uses deactivate_output() instead")
}
fn set_env(&self, _key: &str, _value: &str) -> String {
unimplemented!("Nushell uses hook_env_output() instead")
}
fn unset_env(&self, _key: &str) -> String {
unimplemented!("Nushell uses hook_env_output() instead")
}
fn hook_env_output(
&self,
added: &[(String, String)],
removed: &[String],
session_encoded: &str,
) -> String {
let mut set_map = serde_json::Map::new();
for (key, value) in added {
set_map.insert(key.clone(), serde_json::Value::String(value.clone()));
}
set_map.insert(
"__FNOX_SESSION".to_string(),
serde_json::Value::String(session_encoded.to_string()),
);
let unset_list: Vec<serde_json::Value> = removed
.iter()
.map(|k| serde_json::Value::String(k.clone()))
.collect();
serde_json::json!({"set": set_map, "unset": unset_list}).to_string()
}
fn deactivate_output(&self, secret_keys: &[String]) -> String {
let mut unset_keys: Vec<serde_json::Value> = secret_keys
.iter()
.map(|k| serde_json::Value::String(k.clone()))
.collect();
unset_keys.push(serde_json::Value::String("__FNOX_SESSION".to_string()));
serde_json::json!({"set": {}, "unset": unset_keys}).to_string()
}
}
impl fmt::Display for Nushell {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "nu")
}
}