diff options
Diffstat (limited to 'src/shell_install/nushell.rs')
-rw-r--r-- | src/shell_install/nushell.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/shell_install/nushell.rs b/src/shell_install/nushell.rs new file mode 100644 index 0000000..228a28f --- /dev/null +++ b/src/shell_install/nushell.rs @@ -0,0 +1,123 @@ +//! The goal of this mod is to ensure the launcher shell function +//! is available for nushell i.e. the `br` shell function can +//! be used to launch broot (and thus make it possible to execute +//! some commands, like `cd`, from the starting shell. +//! +//! In a correct installation, we have: +//! - a function declaration script in ~/.local/share/broot/launcher/nushell/br/1 +//! - a link to that script in ~/.config/broot/launcher/nushell/br/1 +//! - a line to source the link in ~/.config/nushell/config.nu +//! (exact paths depend on XDG variables) +//! +//! More info at +//! https://github.com/Canop/broot/issues/375 + +use { + super::{util, ShellInstall}, + crate::{ + conf, + errors::*, + }, + directories::BaseDirs, + std::path::PathBuf, + termimad::{ + mad_print_inline, + }, +}; + +const NAME: &str = "nushell"; +const VERSION: &str = "1"; + +const NU_FUNC: &str = r#" +# This script was automatically generated by the broot program +# More information can be found in https://github.com/Canop/broot +# This function starts broot and executes the command +# it produces, if any. +# It's needed because some shell commands, like `cd`, +# have no useful effect if executed in a subshell. +def _br_cmd [] { + let cmd_file = ([ $nu.temp-path, $"broot-(random chars).tmp" ] | path join) + touch $cmd_file + ^broot --outcmd $cmd_file + let target_dir = (open $cmd_file | to text | str replace "^cd\\s+" "" | str trim) + rm -p -f $cmd_file + + $target_dir +} +alias br = cd (_br_cmd) +"#; + +pub fn get_script() -> &'static str { + NU_FUNC +} + +/// return the path to the link to the function script +fn get_link_path() -> PathBuf { + conf::dir().join("launcher").join(NAME).join("br") +} + +/// return the root of +fn get_nushell_dir() -> Option<PathBuf> { + BaseDirs::new() + .map(|base_dirs| base_dirs.config_dir().join("nushell")) + .filter(|dir| dir.exists()) +} + +/// return the path to the script containing the function. +/// +/// In XDG_DATA_HOME (typically ~/.local/share on linux) +fn get_script_path() -> PathBuf { + conf::app_dirs() + .data_dir() + .join("launcher") + .join(NAME) + .join(VERSION) +} + +/// Check for nushell. +/// +/// Check whether the shell function is installed, install +/// it if it wasn't refused before or if broot is launched +/// with --install. +pub fn install(si: &mut ShellInstall) -> Result<(), ShellInstallError> { + debug!("install {NAME}"); + let Some(nushell_dir) = get_nushell_dir() else { + debug!("no nushell config directory. Assuming nushell isn't used."); + return Ok(()); + }; + info!("nushell seems to be installed"); + let script_path = get_script_path(); + si.write_script(&script_path, NU_FUNC)?; + let link_path = get_link_path(); + si.create_link(&link_path, &script_path)?; + + let escaped_path = link_path.to_string_lossy().replace(' ', "\\ "); + let source_line = format!("source {}", &escaped_path); + + let sourcing_path = nushell_dir.join("config.nu"); + if !sourcing_path.exists() { + warn!("Unexpected lack of config.nu file"); + return Ok(()); + } + if sourcing_path.is_dir() { + warn!("config.nu file"); + return Ok(()); + } + let sourcing_path_str = sourcing_path.to_string_lossy(); + if util::file_contains_line(&sourcing_path, &source_line)? { + mad_print_inline!( + &si.skin, + "`$0` already patched, no change made.\n", + &sourcing_path_str, + ); + } else { + util::append_to_file(&sourcing_path, format!("\n{source_line}\n"))?; + mad_print_inline!( + &si.skin, + "`$0` successfully patched, you can make the function immediately available with `source $0`\n", + &sourcing_path_str, + ); + } + si.done = true; + Ok(()) +} |