diff --git a/README.md b/README.md index 087701d..7ba5550 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,16 @@ some limited ability to make the manipulations dynamic. ![shadowenv in action](https://burkelibbey.s3.amazonaws.com/shadowenv.gif) In order to use shadowenv, add a line to your shell profile (`.zshrc`, `.bash_profile`, -`config.fish`, or `config.nu`) reading: +or `config.fish`) reading: ```bash eval "$(shadowenv init bash)" # for bash eval "$(shadowenv init zsh)" # for zsh shadowenv init fish | source # for fish -# for nushell, paste the output of `shadowenv init nushell` into config.nu ``` +For nushell, run `shadowenv init nushell` which will install a hook into nushell's autoload directory. + With this code loaded, upon entering a directory containing a `.shadowenv.d` directory, any `*.lisp` files in that directory will be executed and you will see "activated shadowenv." in your shell. diff --git a/src/exec_cmd.rs b/src/exec_cmd.rs index e376305..4e3fb7f 100644 --- a/src/exec_cmd.rs +++ b/src/exec_cmd.rs @@ -7,7 +7,7 @@ pub fn run(cmd: ExecCmd) -> Result<(), Error> { let data = Shadowenv::from_env(); let pathbuf = cmd .dir - .map(|d| PathBuf::from(d)) + .map(PathBuf::from) .unwrap_or(get_current_dir_or_exit()); if let Some(shadowenv) = hook::load_env(pathbuf, data, true, false)? { diff --git a/src/init.rs b/src/init.rs index 00027f0..b088d0a 100644 --- a/src/init.rs +++ b/src/init.rs @@ -1,9 +1,12 @@ use crate::cli::InitCmd::{self, *}; +use anyhow::{anyhow, Context, Result}; +use std::fs; use std::path::PathBuf; +use std::process::Command; /// print a script that can be sourced into the provided shell, and sets up the shadowenv shell /// hooks. -pub fn run(cmd: InitCmd) { +pub fn run(cmd: InitCmd) -> Result<()> { let pb = std::env::current_exe().unwrap(); // this would be... an unusual failure. match cmd { Bash(opts) => print_script( @@ -21,15 +24,47 @@ pub fn run(cmd: InitCmd) { include_bytes!("../sh/shadowenv.fish.in"), true, // Fish doesn't use hookbook ), - Nushell => print_script( - pb, - include_bytes!("../sh/shadowenv.nushell.in"), - true, // Nushell doesn't use hookbook - ), - }; + Nushell => install_nushell_hook(pb), + } +} + +fn install_nushell_hook(selfpath: PathBuf) -> Result<()> { + let output = Command::new("nu") + .args(["-c", "$nu.user-autoload-dirs | first"]) + .output() + .map_err(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + anyhow!("Could not find 'nu' in PATH. Please ensure nushell is installed.") + } else { + anyhow!("Failed to run 'nu': {}", e) + } + })?; + + if !output.status.success() { + return Err(anyhow!( + "Failed to query nushell autoload directory: {}", + String::from_utf8_lossy(&output.stderr).trim() + )); + } + + let autoload_dir = String::from_utf8_lossy(&output.stdout).trim().to_string(); + let autoload_path = PathBuf::from(&autoload_dir); + + fs::create_dir_all(&autoload_path) + .with_context(|| format!("Failed to create autoload directory '{}'", autoload_dir))?; + + let script_path = autoload_path.join("shadowenv.nu"); + let script = String::from_utf8_lossy(include_bytes!("../sh/shadowenv.nushell.in")); + let script = script.replace("@SELF@", selfpath.to_str().unwrap()); + + fs::write(&script_path, script.as_bytes()) + .with_context(|| format!("Failed to write '{}'", script_path.display()))?; + + println!("Wrote shadowenv hook to {}", script_path.display()); + Ok(()) } -fn print_script(selfpath: PathBuf, bytes: &[u8], no_hookbook: bool) -> i32 { +fn print_script(selfpath: PathBuf, bytes: &[u8], no_hookbook: bool) -> Result<()> { let script = String::from_utf8_lossy(bytes); let script = script.replace("@SELF@", selfpath.into_os_string().to_str().unwrap()); @@ -44,5 +79,5 @@ fn print_script(selfpath: PathBuf, bytes: &[u8], no_hookbook: bool) -> i32 { let script = script.replace("@HOOKBOOK@", &padded_hookbook); println!("{}", script); } - 0 + Ok(()) } diff --git a/src/lang.rs b/src/lang.rs index e9306ad..84441e4 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -53,7 +53,7 @@ impl ShadowenvWrapper { fn new(shadowenv: Shadowenv) -> Self { Self(RefCell::new(shadowenv)) } - fn borrow_mut_env(&self) -> std::cell::RefMut { + fn borrow_mut_env(&self) -> std::cell::RefMut<'_, Shadowenv> { self.0.borrow_mut() } fn borrow_env(&self) -> Ref<'_, Shadowenv> { diff --git a/src/main.rs b/src/main.rs index 26267a2..cea5a36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,12 +21,18 @@ fn main() { use cli::ShadowenvApp::*; let result = match cli::ShadowenvApp::parse() { - Diff(cmd) => Ok(diff::run(cmd)), + Diff(cmd) => { + diff::run(cmd); + Ok(()) + } Exec(cmd) => exec_cmd::run(cmd), Hook(cmd) => hook::run(cmd), - Init(cmd) => Ok(init::run(cmd)), + Init(cmd) => init::run(cmd), Trust(_) => trust::run(), - PromptWidget(_) => Ok(prompt_widget::run()), + PromptWidget(_) => { + prompt_widget::run(); + Ok(()) + } }; if let Err(err) = result {