Skip to content

Commit

Permalink
feat(complete): Support getting shell from env
Browse files Browse the repository at this point in the history
Add functions for getting the Shell from a path and for getting the
current shell form environment variables.

Closes: #4446
  • Loading branch information
tmccombs committed Nov 7, 2022
1 parent 033438e commit 86db119
Showing 1 changed file with 64 additions and 0 deletions.
64 changes: 64 additions & 0 deletions clap_complete/src/shells/shell.rs
@@ -1,4 +1,5 @@
use std::fmt::Display;
use std::path::Path;
use std::str::FromStr;

use clap::builder::PossibleValue;
Expand Down Expand Up @@ -89,3 +90,66 @@ impl Generator for Shell {
}
}
}

impl Shell {
/// Parse a shell from a path to the executable for the shell
///
/// # Examples
///
/// ```
/// use clap_complete::shells::Shell;
///
/// assert_eq!(Shell::from_shell_path("/bin/bash"), Some(Shell::Bash));
/// assert_eq!(Shell::from_shell_path("/usr/bin/zsh"), Some(Shell::Zsh));
/// assert_eq!(Shell::from_shell_path("/opt/my_custom_shell"), None);
/// ```
pub fn from_shell_path<P: AsRef<Path>>(path: P) -> Option<Shell> {
parse_shell_from_path(path.as_ref())
}

/// Determine the user's current shell from the environment
///
/// This will read the SHELL environment variable and try to determine which shell is in use
/// from that.
///
/// If SHELL is not set, then on windows, it will default to powershell, and on
/// other OSes it will return `None`.
///
/// If SHELL is set, but contains a value that doesn't correspond to one of the supported shell
/// types, then return `None`.
///
/// # Example:
///
/// ```no_run
/// # use clap::Command;
/// use clap_complete::{generate, shells::Shell};
/// # fn build_cli() -> Command {
/// # Command::new("compl")
/// # }
/// let mut cmd = build_cli();
/// generate(Shell::from_env().unwrap_or(Shell::Bash), &mut cmd, "myapp", &mut std::io::stdout());
/// ```
pub fn from_env() -> Option<Shell> {
if let Some(env_shell) = std::env::var_os("SHELL") {
Shell::from_shell_path(env_shell)
} else if cfg!(windows) {
Some(Shell::PowerShell)
} else {
None
}
}
}

// use a separate function to avoid having to monomorphize the entire function due
// to from_shell_path being generic
fn parse_shell_from_path(path: &Path) -> Option<Shell> {
let name = path.file_stem()?.to_str()?;
match name {
"bash" => Some(Shell::Bash),
"zsh" => Some(Shell::Zsh),
"fish" => Some(Shell::Fish),
"elvish" => Some(Shell::Elvish),
"powershell" | "powershell_ise" => Some(Shell::PowerShell),
_ => None,
}
}

0 comments on commit 86db119

Please sign in to comment.