use {
super::{
ShellInstall,
util,
},
crate::{
conf,
errors::*,
},
directories::UserDirs,
lazy_regex::regex,
regex::Captures,
std::{
env,
path::PathBuf,
},
termimad::mad_print_inline,
};
const NAME: &str = "bash";
const SOURCING_FILES: &[&str] = &[".bashrc", ".bash_profile", ".zshrc", "$ZDOTDIR/.zshrc"];
const VERSION: &str = "1";
const BASH_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.
function br {
local cmd cmd_file code
cmd_file=$(mktemp)
if broot --outcmd "$cmd_file" "$@"; then
cmd=$(<"$cmd_file")
command rm -f "$cmd_file"
eval "$cmd"
else
code=$?
command rm -f "$cmd_file"
return "$code"
fi
}
"#;
const MD_NO_SOURCING: &str = r"
I found no sourcing file for the bash/zsh family.
If you're using bash or zsh, then installation isn't complete:
the br function initialization script won't be sourced unless you source it yourself.
";
pub fn get_script() -> &'static str {
BASH_FUNC
}
fn get_link_path() -> PathBuf {
conf::dir().join("launcher").join(NAME).join("br")
}
fn get_script_path() -> PathBuf {
conf::app_dirs()
.data_dir()
.join("launcher")
.join(NAME)
.join(VERSION)
}
fn get_sourcing_paths() -> Vec<PathBuf> {
let homedir_path = UserDirs::new()
.expect("no home directory!")
.home_dir()
.to_path_buf();
SOURCING_FILES
.iter()
.map(|name| {
regex!(r#"\$(\w+)"#)
.replace(name, |c: &Captures<'_>| {
env::var(&c[1]).unwrap_or_else(|_| (*name).to_string())
})
.to_string()
})
.map(PathBuf::from)
.map(|path| {
if path.is_absolute() {
path
} else {
homedir_path.join(path)
}
})
.filter(|path| {
debug!("considering path: {:?}", &path);
path.exists()
})
.collect()
}
pub fn install(si: &mut ShellInstall) -> Result<(), ShellInstallError> {
let script_path = get_script_path();
si.write_script(&script_path, BASH_FUNC)?;
let link_path = get_link_path();
si.create_link(&link_path, &script_path)?;
let sourcing_paths = get_sourcing_paths();
if sourcing_paths.is_empty() {
warn!("no sourcing path for bash/zsh!");
si.skin.print_text(MD_NO_SOURCING);
return Ok(());
}
let escaped_path = link_path.to_string_lossy().replace(' ', "\\ ");
let source_line = format!("source {}", &escaped_path);
for sourcing_path in &sourcing_paths {
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"))?;
let is_zsh = sourcing_path_str.contains(".zshrc");
if is_zsh {
mad_print_inline!(
&si.skin,
"`$0` successfully patched, you can make the function immediately available with `exec zsh`\n",
&sourcing_path_str,
);
} else {
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(())
}