diff --git a/.github/config-schema.json b/.github/config-schema.json index e80ef862..f999866b 100644 --- a/.github/config-schema.json +++ b/.github/config-schema.json @@ -798,6 +798,7 @@ }, "hostname": { "default": { + "detect_env_vars": [], "disabled": false, "format": "[$ssh_symbol$hostname]($style) in ", "ssh_only": true, @@ -3740,6 +3741,13 @@ "default": ".", "type": "string" }, + "detect_env_vars": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, "format": { "default": "[$ssh_symbol$hostname]($style) in ", "type": "string" diff --git a/docs/config/README.md b/docs/config/README.md index 2b171535..ac116b9d 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -2238,14 +2238,15 @@ The `hostname` module shows the system hostname. ### Options -| Option | Default | Description | -| ------------ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| `ssh_only` | `true` | Only show hostname when connected to an SSH session. | -| `ssh_symbol` | `'🌐 '` | A format string representing the symbol when connected to SSH session. | -| `trim_at` | `'.'` | String that the hostname is cut off at, after the first match. `'.'` will stop after the first dot. `''` will disable any truncation | -| `format` | `'[$ssh_symbol$hostname]($style) in '` | The format for the module. | -| `style` | `'bold dimmed green'` | The style for the module. | -| `disabled` | `false` | Disables the `hostname` module. | +| Option | Default | Description | +| ----------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| `ssh_only` | `true` | Only show hostname when connected to an SSH session. | +| `ssh_symbol` | `'🌐 '` | A format string representing the symbol when connected to SSH session. | +| `trim_at` | `'.'` | String that the hostname is cut off at, after the first match. `'.'` will stop after the first dot. `''` will disable any truncation. | +| `detect_env_vars` | `[]` | Which environment variable(s) should trigger this module. | +| `format` | `'[$ssh_symbol$hostname]($style) in '` | The format for the module. | +| `style` | `'bold dimmed green'` | The style for the module. | +| `disabled` | `false` | Disables the `hostname` module. | ### Variables @@ -2257,7 +2258,9 @@ The `hostname` module shows the system hostname. *: This variable can only be used as a part of a style string -### Example +### Examples + +#### Always show the hostname ```toml # ~/.config/starship.toml @@ -2269,6 +2272,17 @@ trim_at = '.companyname.com' disabled = false ``` +#### Hide the hostname in remote tmux sessions + +```toml +# ~/.config/starship.toml + +[hostname] +ssh_only = false +detect_env_vars = ['!TMUX', 'SSH_CONNECTION'] +disabled = false +``` + ## Java The `java` module shows the currently installed version of [Java](https://www.oracle.com/java/). diff --git a/src/configs/hostname.rs b/src/configs/hostname.rs index b6fbfb48..879afa3c 100644 --- a/src/configs/hostname.rs +++ b/src/configs/hostname.rs @@ -11,6 +11,7 @@ pub struct HostnameConfig<'a> { pub ssh_only: bool, pub ssh_symbol: &'a str, pub trim_at: &'a str, + pub detect_env_vars: Vec<&'a str>, pub format: &'a str, pub style: &'a str, pub disabled: bool, @@ -22,6 +23,7 @@ impl<'a> Default for HostnameConfig<'a> { ssh_only: true, ssh_symbol: "🌐 ", trim_at: ".", + detect_env_vars: vec![], format: "[$ssh_symbol$hostname]($style) in ", style: "green dimmed bold", disabled: false, diff --git a/src/context.rs b/src/context.rs index 124b5ced..a0753009 100644 --- a/src/context.rs +++ b/src/context.rs @@ -235,8 +235,32 @@ impl<'a> Context<'a> { disabled == Some(true) } + /// Returns true when a negated environment variable is defined in `env_vars` and is present + fn has_negated_env_var(&self, env_vars: &'a [&'a str]) -> bool { + env_vars + .iter() + .filter_map(|env_var| env_var.strip_prefix('!')) + .any(|env_var| self.get_env(env_var).is_some()) + } + + /// Returns true if 'detect_env_vars' is empty, + /// or if at least one environment variable is set and no negated environment variable is set pub fn detect_env_vars(&'a self, env_vars: &'a [&'a str]) -> bool { - env_vars.is_empty() || (env_vars.iter().any(|e| self.get_env(e).is_some())) + if env_vars.is_empty() { + return true; + } + + if self.has_negated_env_var(env_vars) { + return false; + } + + // Returns true if at least one environment variable is set + let mut iter = env_vars + .iter() + .filter(|env_var| !env_var.starts_with('!')) + .peekable(); + + iter.peek().is_none() || iter.any(|env_var| self.get_env(env_var).is_some()) } // returns a new ScanDir struct with reference to current dir_files of context diff --git a/src/modules/hostname.rs b/src/modules/hostname.rs index d476dcf4..8eec9b5f 100644 --- a/src/modules/hostname.rs +++ b/src/modules/hostname.rs @@ -8,14 +8,18 @@ use crate::formatter::StringFormatter; /// Creates a module with the system hostname /// /// Will display the hostname if all of the following criteria are met: -/// - hostname.disabled is absent or false +/// - `hostname.disabled` is absent or false /// - `hostname.ssh_only` is false OR the user is currently connected as an SSH session (`$SSH_CONNECTION`) +/// - `hostname.ssh_only` is false AND `hostname.detect_env_vars` is either empty or contains a defined environment variable pub fn module<'a>(context: &'a Context) -> Option> { let mut module = context.new_module("hostname"); let config: HostnameConfig = HostnameConfig::try_load(module.config); let ssh_connection = context.get_env("SSH_CONNECTION"); - if config.ssh_only && ssh_connection.is_none() { + + if (config.ssh_only && ssh_connection.is_none()) + || !context.detect_env_vars(&config.detect_env_vars) + { return None; } @@ -96,17 +100,82 @@ mod tests { } #[test] - fn ssh_only_false_no_ssh() { + fn ssh_only_false_with_empty_detect_env_vars() { let hostname = get_hostname!(); let actual = ModuleRenderer::new("hostname") .config(toml::toml! { [hostname] ssh_only = false trim_at = "" + detect_env_vars = [] }) .collect(); + let expected = Some(format!("{} in ", style().paint(hostname))); - println!("{}", expected.as_ref().unwrap()); + assert_eq!(expected, actual); + } + + #[test] + fn ssh_only_false_with_matching_negated_env_var() { + let actual = ModuleRenderer::new("hostname") + .config(toml::toml! { + [hostname] + ssh_only = false + trim_at = "" + detect_env_vars = ["!NEGATED"] + }) + .env("NEGATED", "true") + .collect(); + let expected = None; + + assert_eq!(expected, actual); + } + + #[test] + fn ssh_only_false_with_only_negated_env_vars() { + let hostname = get_hostname!(); + let actual = ModuleRenderer::new("hostname") + .config(toml::toml! { + [hostname] + ssh_only = false + trim_at = "" + detect_env_vars = ["!NEGATED_ONE", "!NEGATED_TWO", "!NEGATED_THREE"] + }) + .collect(); + + let expected = Some(format!("{} in ", style().paint(hostname))); + assert_eq!(expected, actual); + } + + #[test] + fn ssh_only_false_with_matching_env_var() { + let hostname = get_hostname!(); + let actual = ModuleRenderer::new("hostname") + .config(toml::toml! { + [hostname] + ssh_only = false + trim_at = "" + detect_env_vars = ["FORCE_HOSTNAME"] + }) + .env("FORCE_HOSTNAME", "true") + .collect(); + + let expected = Some(format!("{} in ", style().paint(hostname))); + assert_eq!(expected, actual); + } + + #[test] + fn ssh_only_false_without_matching_env_vars() { + let actual = ModuleRenderer::new("hostname") + .config(toml::toml! { + [hostname] + ssh_only = false + trim_at = "" + detect_env_vars = ["FORCE_HOSTNAME", "!NEGATED"] + }) + .collect(); + let expected = None; + assert_eq!(expected, actual); } @@ -121,6 +190,7 @@ mod tests { }) .collect(); let expected = Some(format!("{} in ", style().paint(hostname))); + assert_eq!(expected, actual); }