From 37d3425d219fef5e9de60ef29295f1bb7b57e94b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Rosowski?= <49301780+rosowskimik@users.noreply.github.com> Date: Sat, 20 Feb 2021 14:40:49 +0000 Subject: [PATCH] feat: create shell module (#2329) * Add the shell module This module allows to quickly identify which shell is currently used, in case someone frequently switches between them. * Updated documentation with shell module. Co-authored-by: mro --- docs/config/README.md | 41 ++++++ src/configs/mod.rs | 1 + src/configs/shell.rs | 30 +++++ src/configs/starship_root.rs | 1 + src/module.rs | 1 + src/modules/mod.rs | 3 + src/modules/shell.rs | 239 +++++++++++++++++++++++++++++++++++ 7 files changed, 316 insertions(+) create mode 100644 src/configs/shell.rs create mode 100644 src/modules/shell.rs diff --git a/docs/config/README.md b/docs/config/README.md index 8fe4a631..f2438edd 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -236,6 +236,7 @@ $jobs\ $battery\ $time\ $status\ +$shell\ $character""" ``` @@ -2217,6 +2218,46 @@ The module will be shown if any of the following conditions are met: format = "via [⚙️ $version](red bold)" ``` +## Shell + +The `shell` module shows an indicator for currently used shell. + +::: tip + +This module is disabled by default. +To enable it, set `disabled` to `false` in your configuration file. + +::: + +### Options + +| Option | Default | Description | +| ---------------------- | ------------- | --------------------------------------------- | +| `bash_indicator` | `bsh` | A format string used to represent bash. | +| `fish_indicator` | `fsh` | A format string used to represent fish. | +| `zsh_indicator` | `zsh` | A format string used to represent zsh. | +| `powershell_indicator` | `psh` | A format string used to represent powershell. | +| `ion_indicator` | `ion` | A format string used to represent ion. | +| `elvish_indicator` | `esh` | A format string used to represent elvish. | +| `format` | `$indicator ` | The format for the module. | +| `disabled` | `true` | Disables the `shell` module. | + +### Variables + +| Variable | Default | Description | +| ----------- | ------- | ---------------------------------------------------------- | +| indicator | | Mirrors the value of `indicator` for currently used shell. | + +### Examples +```toml +# ~/.config/starship.toml + +[shell] +fish_indicator = "" +powershell_indicator = "_" +disabled = false +``` + ## SHLVL The `shlvl` module shows the current SHLVL ("shell level") environment variable, if it is diff --git a/src/configs/mod.rs b/src/configs/mod.rs index 91d3b106..1052a673 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -42,6 +42,7 @@ pub mod purescript; pub mod python; pub mod ruby; pub mod rust; +pub mod shell; pub mod shlvl; pub mod singularity; mod starship_root; diff --git a/src/configs/shell.rs b/src/configs/shell.rs new file mode 100644 index 00000000..24551df9 --- /dev/null +++ b/src/configs/shell.rs @@ -0,0 +1,30 @@ +use crate::config::{ModuleConfig, RootModuleConfig}; + +use starship_module_config_derive::ModuleConfig; + +#[derive(Clone, ModuleConfig)] +pub struct ShellConfig<'a> { + pub format: &'a str, + pub bash_indicator: &'a str, + pub fish_indicator: &'a str, + pub zsh_indicator: &'a str, + pub powershell_indicator: &'a str, + pub ion_indicator: &'a str, + pub elvish_indicator: &'a str, + pub disabled: bool, +} + +impl<'a> RootModuleConfig<'a> for ShellConfig<'a> { + fn new() -> Self { + ShellConfig { + format: "$indicator ", + bash_indicator: "bsh", + fish_indicator: "fsh", + zsh_indicator: "zsh", + powershell_indicator: "psh", + ion_indicator: "ion", + elvish_indicator: "esh", + disabled: true, + } + } +} diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index 0c9ccc8f..a73f0229 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -71,6 +71,7 @@ pub const PROMPT_ORDER: &[&str] = &[ "battery", "time", "status", + "shell", "character", ]; diff --git a/src/module.rs b/src/module.rs index 431a3790..e222ef2e 100644 --- a/src/module.rs +++ b/src/module.rs @@ -56,6 +56,7 @@ pub const ALL_MODULES: &[&str] = &[ "php", "swift", "terraform", + "shell", "shlvl", "singularity", "status", diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 91872b36..207d4e66 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -43,6 +43,7 @@ mod purescript; mod python; mod ruby; mod rust; +mod shell; mod shlvl; mod singularity; mod status; @@ -113,6 +114,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "python" => python::module(context), "ruby" => ruby::module(context), "rust" => rust::module(context), + "shell" => shell::module(context), "shlvl" => shlvl::module(context), "singularity" => singularity::module(context), "swift" => swift::module(context), @@ -191,6 +193,7 @@ pub fn description(module: &str) -> &'static str { "ruby" => "The currently installed version of Ruby", "rust" => "The currently installed version of Rust", "swift" => "The currently installed version of Swift", + "shell" => "The currently used shell indicator", "shlvl" => "The current value of SHLVL", "status" => "The status of the last command", "terraform" => "The currently selected terraform workspace and version", diff --git a/src/modules/shell.rs b/src/modules/shell.rs new file mode 100644 index 00000000..fe90b2e8 --- /dev/null +++ b/src/modules/shell.rs @@ -0,0 +1,239 @@ +use super::{Context, Module, RootModuleConfig, Shell}; + +use crate::configs::shell::ShellConfig; +use crate::formatter::StringFormatter; + +pub fn module<'a>(context: &'a Context) -> Option> { + let mut module = context.new_module("shell"); + let config: ShellConfig = ShellConfig::try_load(module.config); + + if config.disabled { + return None; + } + + let shell = context.shell; + + let parsed = StringFormatter::new(config.format).and_then(|formatter| { + formatter + .map_meta(|variable, _| match variable { + "indicator" => match shell { + Shell::Bash => Some(config.bash_indicator), + Shell::Fish => Some(config.fish_indicator), + Shell::Zsh => Some(config.zsh_indicator), + Shell::PowerShell => Some(config.powershell_indicator), + Shell::Ion => Some(config.ion_indicator), + Shell::Elvish => Some(config.elvish_indicator), + Shell::Unknown => None, + }, + _ => None, + }) + .parse(None) + }); + + module.set_segments(match parsed { + Ok(segments) => segments, + Err(error) => { + log::warn!("Error in module `shell`: \n{}", error); + return None; + } + }); + + Some(module) +} + +#[cfg(test)] +mod tests { + use crate::context::Shell; + use crate::test::ModuleRenderer; + use ansi_term::Color; + + #[test] + fn test_none_if_disabled() { + let expected = None; + let actual = ModuleRenderer::new("shell").shell(Shell::Bash).collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_none_if_unknown_shell() { + let expected = None; + let actual = ModuleRenderer::new("shell").shell(Shell::Unknown).collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_bash_default_format() { + let expected = Some(format!("{} ", "bsh")); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Bash) + .config(toml::toml! { + [shell] + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_bash_custom_format() { + let expected = Some(format!("{} ", Color::Cyan.bold().paint("bash"))); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Bash) + .config(toml::toml! { + [shell] + bash_indicator = "[bash](bold cyan)" + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_fish_default_format() { + let expected = Some(format!("{} ", "fsh")); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Fish) + .config(toml::toml! { + [shell] + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_fish_custom_format() { + let expected = Some(format!("{} ", Color::Cyan.bold().paint("fish"))); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Fish) + .config(toml::toml! { + [shell] + fish_indicator = "[fish](cyan bold)" + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_zsh_default_format() { + let expected = Some(format!("{} ", "zsh")); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Zsh) + .config(toml::toml! { + [shell] + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_zsh_custom_format() { + let expected = Some(format!("{} ", Color::Cyan.bold().paint("zsh"))); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Bash) + .config(toml::toml! { + [shell] + bash_indicator = "[zsh](bold cyan)" + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_powershell_default_format() { + let expected = Some(format!("{} ", "psh")); + let actual = ModuleRenderer::new("shell") + .shell(Shell::PowerShell) + .config(toml::toml! { + [shell] + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_powershell_custom_format() { + let expected = Some(format!("{} ", Color::Cyan.bold().paint("powershell"))); + let actual = ModuleRenderer::new("shell") + .shell(Shell::PowerShell) + .config(toml::toml! { + [shell] + powershell_indicator = "[powershell](bold cyan)" + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_ion_default_format() { + let expected = Some(format!("{} ", "ion")); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Ion) + .config(toml::toml! { + [shell] + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_ion_custom_format() { + let expected = Some(format!("{} ", Color::Cyan.bold().paint("ion"))); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Ion) + .config(toml::toml! { + [shell] + ion_indicator = "[ion](bold cyan)" + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_elvish_default_format() { + let expected = Some(format!("{} ", "esh")); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Elvish) + .config(toml::toml! { + [shell] + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_elvish_custom_format() { + let expected = Some(format!("{} ", Color::Cyan.bold().paint("elvish"))); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Elvish) + .config(toml::toml! { + [shell] + elvish_indicator = "[elvish](bold cyan)" + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } +}