Skip to main content

starbase_shell/shells/
mod.rs

1mod ash;
2mod bash;
3mod elvish;
4mod fish;
5mod ion;
6mod murex;
7mod nu;
8mod powershell;
9mod pwsh;
10mod sh;
11mod xonsh;
12mod zsh;
13
14pub use ash::*;
15pub use bash::*;
16pub use elvish::*;
17pub use fish::*;
18pub use ion::*;
19pub use murex::*;
20pub use nu::*;
21pub use powershell::*;
22pub use pwsh::*;
23pub use sh::*;
24pub use xonsh::*;
25pub use zsh::*;
26
27use crate::helpers::get_env_var_regex;
28use crate::hooks::*;
29use crate::quoter::*;
30use crate::shell_error::ShellError;
31use shell_quote::Quotable;
32use std::ffi::OsString;
33use std::fmt::{Debug, Display};
34use std::path::{Path, PathBuf};
35
36#[derive(Debug)]
37pub struct ShellCommand {
38    pub shell_args: Vec<OsString>,
39    pub pass_args_stdin: bool,
40}
41
42impl Default for ShellCommand {
43    fn default() -> Self {
44        // This is pretty much the same for all shells except pwsh.
45        // bash -c "command", nu -c "command", etc...
46        Self {
47            shell_args: vec![OsString::from("-c")],
48            pass_args_stdin: false,
49        }
50    }
51}
52
53pub trait Shell: Debug + Display + Send + Sync {
54    /// Create a quoter for the provided string.
55    fn create_quoter<'a>(&self, data: Quotable<'a>) -> Quoter<'a>;
56
57    /// Format the provided statement.
58    fn format(&self, statement: Statement<'_>) -> String;
59
60    /// Format an environment variable by either setting or unsetting the value.
61    fn format_env(&self, key: &str, value: Option<&str>) -> String {
62        match value {
63            Some(value) => self.format_env_set(key, value),
64            None => self.format_env_unset(key),
65        }
66    }
67
68    /// Format an environment variable that will be set to the entire shell.
69    fn format_env_set(&self, key: &str, value: &str) -> String {
70        self.format(Statement::SetEnv { key, value })
71    }
72
73    /// Format an environment variable that will be unset from the entire shell.
74    fn format_env_unset(&self, key: &str) -> String {
75        self.format(Statement::UnsetEnv { key })
76    }
77
78    /// Format the provided paths to prepend the `PATH` environment variable.
79    fn format_path_prepend(&self, paths: &[String]) -> String {
80        self.format(Statement::ModifyPath {
81            paths,
82            key: Some("PATH"),
83            orig_key: Some("PATH"),
84        })
85    }
86
87    /// Format the provided paths to override the `PATH` environment variable.
88    fn format_path_set(&self, paths: &[String]) -> String {
89        self.format(Statement::ModifyPath {
90            paths,
91            key: Some("PATH"),
92            orig_key: None,
93        })
94    }
95
96    /// Format a hook for the current shell.
97    fn format_hook(&self, hook: Hook) -> Result<String, ShellError> {
98        Err(ShellError::NoHookSupport {
99            name: self.to_string(),
100            info: hook.get_info().to_owned(),
101        })
102    }
103
104    /// Return the path in which commands, aliases, and other settings will be configured.
105    fn get_config_path(&self, home_dir: &Path) -> PathBuf;
106
107    /// Return the path in which environment settings will be defined.
108    fn get_env_path(&self, home_dir: &Path) -> PathBuf;
109
110    /// Return a regex pattern for matching against environment variables.
111    fn get_env_regex(&self) -> regex::Regex {
112        get_env_var_regex()
113    }
114
115    /// Return parameters for executing a one-off command and then exiting.
116    fn get_exec_command(&self) -> ShellCommand {
117        ShellCommand::default()
118    }
119
120    /// Return a list of all possible profile/rc/config paths.
121    /// Ordered from most to least common/applicable.
122    fn get_profile_paths(&self, home_dir: &Path) -> Vec<PathBuf>;
123
124    /// Quote the provided string.
125    fn quote(&self, value: &str) -> String {
126        self.create_quoter(Quotable::from(value)).maybe_quote()
127    }
128}
129
130pub type BoxedShell = Box<dyn Shell>;