aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--atuin/src/command/client/doctor.rs115
-rw-r--r--atuin/src/shell/atuin.bash5
2 files changed, 99 insertions, 21 deletions
diff --git a/atuin/src/command/client/doctor.rs b/atuin/src/command/client/doctor.rs
index ef399e7d..5c144fed 100644
--- a/atuin/src/command/client/doctor.rs
+++ b/atuin/src/command/client/doctor.rs
@@ -1,5 +1,5 @@
use std::process::Command;
-use std::{collections::HashMap, path::PathBuf};
+use std::{env, path::PathBuf, str::FromStr};
use atuin_client::settings::Settings;
use colored::Colorize;
@@ -19,12 +19,12 @@ struct ShellInfo {
impl ShellInfo {
// HACK ALERT!
- // Many of the env vars we need to detect are not exported :(
- // So, we're going to run `env` in a subshell and parse the output
- // There's a chance this won't work, so it should not be fatal.
+ // Many of the shell vars we need to detect are not exported :(
+ // So, we're going to run a interactive session and directly check the
+ // variable. There's a chance this won't work, so it should not be fatal.
//
- // Every shell we support handles `shell -c 'command'`
- fn env_exists(shell: &str, var: &str) -> bool {
+ // Every shell we support handles `shell -ic 'command'`
+ fn shellvar_exists(shell: &str, var: &str) -> bool {
let cmd = Command::new(shell)
.args([
"-ic",
@@ -39,23 +39,96 @@ impl ShellInfo {
cmd.contains("ATUIN_DOCTOR_ENV_FOUND")
}
- pub fn plugins(shell: &str) -> Vec<String> {
+ fn validate_plugin_blesh(
+ _shell: &str,
+ shell_process: &sysinfo::Process,
+ ble_session_id: &str,
+ ) -> Option<String> {
+ ble_session_id
+ .split('/')
+ .nth(1)
+ .and_then(|field| u32::from_str(field).ok())
+ .filter(|&blesh_pid| blesh_pid == shell_process.pid().as_u32())
+ .map(|_| "blesh".to_string())
+ }
+
+ pub fn plugins(shell: &str, shell_process: &sysinfo::Process) -> Vec<String> {
// consider a different detection approach if there are plugins
- // that don't set env vars
+ // that don't set shell vars
- let map = HashMap::from([
- ("ATUIN_SESSION", "atuin"),
- ("BLE_ATTACHED", "blesh"),
- ("bash_preexec_imported", "bash-preexec"),
- ]);
+ enum PluginShellType {
+ Any,
+ Bash,
- map.into_iter()
- .filter_map(|(env, plugin)| {
- if ShellInfo::env_exists(shell, env) {
- return Some(plugin.to_string());
- }
+ // Note: these are currently unused
+ #[allow(dead_code)]
+ Zsh,
+ #[allow(dead_code)]
+ Fish,
+ #[allow(dead_code)]
+ Nushell,
+ #[allow(dead_code)]
+ Xonsh,
+ }
+
+ enum PluginProbeType {
+ EnvironmentVariable(&'static str),
+ InteractiveShellVariable(&'static str),
+ }
+
+ type PluginValidator = fn(&str, &sysinfo::Process, &str) -> Option<String>;
+
+ let plugin_list: [(
+ &str,
+ PluginShellType,
+ PluginProbeType,
+ Option<PluginValidator>,
+ ); 3] = [
+ (
+ "atuin",
+ PluginShellType::Any,
+ PluginProbeType::EnvironmentVariable("ATUIN_SESSION"),
+ None,
+ ),
+ (
+ "blesh",
+ PluginShellType::Bash,
+ PluginProbeType::EnvironmentVariable("BLE_SESSION_ID"),
+ Some(Self::validate_plugin_blesh),
+ ),
+ (
+ "bash-preexec",
+ PluginShellType::Bash,
+ PluginProbeType::InteractiveShellVariable("bash_preexec_imported"),
+ None,
+ ),
+ ];
- None
+ plugin_list
+ .into_iter()
+ .filter(|(_, shell_type, _, _)| match shell_type {
+ PluginShellType::Any => true,
+ PluginShellType::Bash => shell.starts_with("bash") || shell == "sh",
+ PluginShellType::Zsh => shell.starts_with("zsh"),
+ PluginShellType::Fish => shell.starts_with("fish"),
+ PluginShellType::Nushell => shell.starts_with("nu"),
+ PluginShellType::Xonsh => shell.starts_with("xonsh"),
+ })
+ .filter_map(|(plugin, _, probe_type, validator)| -> Option<String> {
+ match probe_type {
+ PluginProbeType::EnvironmentVariable(env) => {
+ env::var(env).ok().filter(|value| !value.is_empty())
+ }
+ PluginProbeType::InteractiveShellVariable(shellvar) => {
+ ShellInfo::shellvar_exists(shell, shellvar).then_some(String::default())
+ }
+ }
+ .and_then(|value| {
+ validator.map_or_else(
+ || Some(plugin.to_string()),
+ |validator| validator(shell, shell_process, &value),
+ )
+ })
})
.collect()
}
@@ -75,7 +148,7 @@ impl ShellInfo {
let shell = shell.strip_prefix('-').unwrap_or(&shell);
let name = shell.to_string();
- let plugins = ShellInfo::plugins(name.as_str());
+ let plugins = ShellInfo::plugins(name.as_str(), parent);
Self { name, plugins }
}
@@ -188,7 +261,7 @@ fn checks(info: &DoctorDump) {
println!(); // spacing
//
let zfs_error = "[Filesystem] ZFS is known to have some issues with SQLite. Atuin uses SQLite heavily. If you are having poor performance, there are some workarounds here: https://github.com/atuinsh/atuin/issues/952".bold().red();
- let bash_plugin_error = "[Shell] If you are using Bash, Atuin requires that either bash-preexec or ble.sh be installed. We cannot currently detect ble, so if you have it setup then ignore this! Read more here: https://docs.atuin.sh/guide/installation/#bash".bold().red();
+ let bash_plugin_error = "[Shell] If you are using Bash, Atuin requires that either bash-preexec or ble.sh be installed. An older ble.sh may not be detected. so ignore this if you have it set up! Read more here: https://docs.atuin.sh/guide/installation/#bash".bold().red();
// ZFS: https://github.com/atuinsh/atuin/issues/952
if info.system.disks.iter().any(|d| d.filesystem == "zfs") {
diff --git a/atuin/src/shell/atuin.bash b/atuin/src/shell/atuin.bash
index 38f58c59..ba4f2cc2 100644
--- a/atuin/src/shell/atuin.bash
+++ b/atuin/src/shell/atuin.bash
@@ -271,6 +271,11 @@ if [[ ${BLE_VERSION-} ]] && ((_ble_version >= 400)); then
}
ble/util/import/eval-after-load core-complete '
ble/array#unshift _ble_complete_auto_source atuin-history'
+
+ # @env BLE_SESSION_ID: `atuin doctor` references the environment variable
+ # BLE_SESSION_ID. We explicitly export the variable because it was not
+ # exported in older versions of ble.sh.
+ [[ ${BLE_SESSION_ID-} ]] && export BLE_SESSION_ID
fi
precmd_functions+=(__atuin_precmd)
preexec_functions+=(__atuin_preexec)