diff --git a/.github/config-schema.json b/.github/config-schema.json index 914693c34..384dd0c79 100644 --- a/.github/config-schema.json +++ b/.github/config-schema.json @@ -622,6 +622,20 @@ } ] }, + "git_mob": { + "default": { + "disabled": true, + "format": "[$symbol $initials \\($count\\)]($style)", + "separator": ",", + "style": "green bold", + "symbol": "👥" + }, + "allOf": [ + { + "$ref": "#/definitions/GitMobConfig" + } + ] + }, "git_state": { "default": { "am": "AM", @@ -3379,6 +3393,32 @@ }, "additionalProperties": false }, + "GitMobConfig": { + "type": "object", + "properties": { + "format": { + "default": "[$symbol $initials \\($count\\)]($style)", + "type": "string" + }, + "style": { + "default": "green bold", + "type": "string" + }, + "symbol": { + "default": "👥", + "type": "string" + }, + "disabled": { + "default": true, + "type": "boolean" + }, + "separator": { + "default": ",", + "type": "string" + } + }, + "additionalProperties": false + }, "GitStateConfig": { "type": "object", "properties": { diff --git a/docs/config/README.md b/docs/config/README.md index 046ad01d4..7f6dc98dc 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -279,6 +279,7 @@ $git_branch\ $git_commit\ $git_state\ $git_metrics\ +$git_mob\ $git_status\ $hg_branch\ $pijul_channel\ @@ -1939,6 +1940,44 @@ added_style = 'bold blue' format = '[+$added]($added_style)/[-$deleted]($deleted_style) ' ``` +## Git Mob + +The `git_mob` module will show the configured Co-Author initials. + +::: tip + +This module is disabled by default. +To enable it, set `disabled` to `false` in your configuration file. + +::: + +### Options + +| Option | Default | Description | +| ----------- | -------------------------------------------- | --------------------------------- | +| `disabled` | `true` | Disables the `git_mob` module. | +| `format` | `'[$symbol $initials \\($count\\)]($style)'` | The format for the module. | +| `separator` | `','` | Separator for multiple Co-Authors | +| `style` | `'green bold'` | Style for the module | +| `symbol` | `'👥 '` | Symbol to display | + +### Variables + +| Variable | Example | Description | +| -------- | ------- | ------------------------------------------------------------- | +| initials | `ab,ce` | The Co-Author initials separated using the provided separator | +| count | `2` | The count of configured Co-Authors | + +### Example + +```toml +# ~/.config/starship.toml + +[git_mob] +disabled = false +separator = "," +``` + ## Git Status The `git_status` module shows symbols representing the state of the repo in your diff --git a/src/configs/git_mob.rs b/src/configs/git_mob.rs new file mode 100644 index 000000000..e759b29f7 --- /dev/null +++ b/src/configs/git_mob.rs @@ -0,0 +1,28 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Deserialize, Serialize)] +#[cfg_attr( + feature = "config-schema", + derive(schemars::JsonSchema), + schemars(deny_unknown_fields) +)] +#[serde(default)] +pub struct GitMobConfig<'a> { + pub format: &'a str, + pub style: &'a str, + pub symbol: &'a str, + pub disabled: bool, + pub separator: &'a str, +} + +impl<'a> Default for GitMobConfig<'a> { + fn default() -> Self { + GitMobConfig { + format: "[$symbol $initials \\($count\\)]($style)", + style: "green bold", + symbol: "👥", + disabled: true, + separator: ",", + } + } +} diff --git a/src/configs/mod.rs b/src/configs/mod.rs index c2cf0a8d9..ff3d552c8 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -34,6 +34,7 @@ pub mod gcloud; pub mod git_branch; pub mod git_commit; pub mod git_metrics; +pub mod git_mob; pub mod git_state; pub mod git_status; pub mod go; @@ -174,6 +175,8 @@ pub struct FullConfig<'a> { #[serde(borrow)] git_metrics: git_metrics::GitMetricsConfig<'a>, #[serde(borrow)] + git_mob: git_mob::GitMobConfig<'a>, + #[serde(borrow)] git_state: git_state::GitStateConfig<'a>, #[serde(borrow)] git_status: git_status::GitStatusConfig<'a>, diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index 86fe7e754..a1c8c7874 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -45,6 +45,7 @@ pub const PROMPT_ORDER: &[&str] = &[ "git_commit", "git_state", "git_metrics", + "git_mob", "git_status", "hg_branch", "pijul_channel", diff --git a/src/module.rs b/src/module.rs index 0dcc0aad4..d3a568da4 100644 --- a/src/module.rs +++ b/src/module.rs @@ -41,6 +41,7 @@ pub const ALL_MODULES: &[&str] = &[ "git_branch", "git_commit", "git_metrics", + "git_mob", "git_state", "git_status", "golang", diff --git a/src/modules/git_mob.rs b/src/modules/git_mob.rs new file mode 100644 index 000000000..564209750 --- /dev/null +++ b/src/modules/git_mob.rs @@ -0,0 +1,166 @@ +use super::{Context, Module, ModuleConfig}; + +use crate::configs::git_mob::GitMobConfig; +use crate::formatter::StringFormatter; + +pub fn module<'a>(context: &'a Context) -> Option> { + let mut module = context.new_module("git_mob"); + let config: GitMobConfig = GitMobConfig::try_load(module.config); + + if config.disabled { + return None; + }; + + let mob_authors = parse_git_mob_authors( + &context + .exec_cmd("git", &["mob-print", "--initials"])? + .stdout, + ); + + let parsed = StringFormatter::new(config.format).and_then(|formatter| { + formatter + .map_meta(|var, _| match var { + "separator" => Some(config.separator), + "symbol" => Some(config.symbol), + _ => None, + }) + .map_style(|variable| match variable { + "style" => Some(Ok(config.style)), + _ => None, + }) + .map(|variable| match variable { + "initials" => Some(Ok(mob_authors.join(config.separator))), + "count" => Some(Ok(mob_authors.len().to_string())), + _ => None, + }) + .parse(None, Some(context)) + }); + + module.set_segments(match parsed { + Ok(segments) => segments, + Err(error) => { + log::warn!("Error in module `git_mob`:\n{}", error); + return None; + } + }); + + Some(module) +} + +fn parse_git_mob_authors(git_mob_stdout: &str) -> Vec { + return git_mob_stdout.split(',').map(|s| s.to_owned()).collect(); +} + +#[cfg(test)] +mod tests { + use crate::test::{fixture_repo, FixtureProvider, ModuleRenderer}; + use crate::utils::CommandOutput; + use nu_ansi_term::Color; + use std::io; + + #[test] + fn nothing_on_empty_dir() -> io::Result<()> { + let repo_dir = tempfile::tempdir()?; + + let actual = ModuleRenderer::new("git_mob") + .path(repo_dir.path()) + .config(toml::toml! { + [git_mob] + enabled = true + }) + .collect(); + + let expected = None; + + assert_eq!(expected, actual); + repo_dir.close() + } + + #[test] + fn nothing_on_disabled() -> io::Result<()> { + let repo_dir = fixture_repo(FixtureProvider::Git)?; + + let actual = ModuleRenderer::new("git_mob") + .path(repo_dir.path()) + .config(toml::toml! { + [git_mob] + disabled = true + }) + .collect(); + + let expected = None; + + assert_eq!(expected, actual); + repo_dir.close() + } + + #[test] + fn nothing_on_not_existing_cmd() -> io::Result<()> { + let repo_dir = tempfile::tempdir()?; + + let actual = ModuleRenderer::new("git_mob") + .path(repo_dir.path()) + .config(toml::toml! { + [git_mob] + disabled = false + }) + .cmd("git mob-print --initials", None) + .collect(); + + let expected = None; + + assert_eq!(expected, actual); + repo_dir.close() + } + + #[test] + fn initials_and_count() -> io::Result<()> { + let repo_dir = tempfile::tempdir()?; + + let actual = ModuleRenderer::new("git_mob") + .path(repo_dir.path()) + .config(toml::toml! { + [git_mob] + disabled = false + }) + .cmd( + "git mob-print --initials", + Some(CommandOutput { + stdout: String::from("ab,ca,de"), + stderr: String::default(), + }), + ) + .collect(); + + let expected = Some(format!("{}", Color::Green.bold().paint("👥 ab,ca,de (3)"))); + + assert_eq!(expected, actual); + repo_dir.close() + } + + #[test] + fn initials_with_custom_separator() -> io::Result<()> { + let repo_dir = tempfile::tempdir()?; + + let actual = ModuleRenderer::new("git_mob") + .path(repo_dir.path()) + .config(toml::toml! { + [git_mob] + disabled = false + separator = "|" + }) + .cmd( + "git mob-print --initials", + Some(CommandOutput { + stdout: String::from("ab,ca,de"), + stderr: String::default(), + }), + ) + .collect(); + + let expected = Some(format!("{}", Color::Green.bold().paint("👥 ab|ca|de (3)"))); + + assert_eq!(expected, actual); + repo_dir.close() + } +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 57983cd1e..07a40c1db 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -31,6 +31,7 @@ mod gcloud; mod git_branch; mod git_commit; mod git_metrics; +mod git_mob; mod git_state; mod git_status; mod golang; @@ -138,6 +139,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "git_branch" => git_branch::module(context), "git_commit" => git_commit::module(context), "git_metrics" => git_metrics::module(context), + "git_mob" => git_mob::module(context), "git_state" => git_state::module(context), "git_status" => git_status::module(context), "golang" => golang::module(context), @@ -256,6 +258,7 @@ pub fn description(module: &str) -> &'static str { "git_branch" => "The active branch of the repo in your current directory", "git_commit" => "The active commit (and tag if any) of the repo in your current directory", "git_metrics" => "The currently added/deleted lines in your repo", + "git_mob" => "Current configured Co-Authors using the git-mob tool", "git_state" => "The current git operation, and it's progress", "git_status" => "Symbol representing the state of the repo", "golang" => "The currently installed version of Golang",