diff --git a/docs/config/README.md b/docs/config/README.md index d1a81b7a..122ca6e2 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -1030,6 +1030,7 @@ The `git_branch` module shows the active branch of the repo in your current dire | `style` | `"bold purple"` | The style for the module. | | `truncation_length` | `2^63 - 1` | Truncates a git branch to X graphemes. | | `truncation_symbol` | `"…"` | The symbol used to indicate a branch name was truncated. You can use `""` for no symbol. | +| `only_attached` | `false` | Only show the branch name when not in a detached HEAD state. | | `disabled` | `false` | Disables the `git_branch` module. | ### Variables diff --git a/src/configs/git_branch.rs b/src/configs/git_branch.rs index 35264798..b3e8f7a3 100644 --- a/src/configs/git_branch.rs +++ b/src/configs/git_branch.rs @@ -9,6 +9,7 @@ pub struct GitBranchConfig<'a> { pub style: &'a str, pub truncation_length: i64, pub truncation_symbol: &'a str, + pub only_attached: bool, pub disabled: bool, } @@ -20,6 +21,7 @@ impl<'a> RootModuleConfig<'a> for GitBranchConfig<'a> { style: "bold purple", truncation_length: std::i64::MAX, truncation_symbol: "…", + only_attached: false, disabled: false, } } diff --git a/src/modules/git_branch.rs b/src/modules/git_branch.rs index 0610b530..55d80866 100644 --- a/src/modules/git_branch.rs +++ b/src/modules/git_branch.rs @@ -1,6 +1,7 @@ use unicode_segmentation::UnicodeSegmentation; use super::{Context, Module, RootModuleConfig}; +use git2::Repository; use crate::configs::git_branch::GitBranchConfig; use crate::formatter::StringFormatter; @@ -25,6 +26,14 @@ pub fn module<'a>(context: &'a Context) -> Option> { }; let repo = context.get_repo().ok()?; + + let repo_root = repo.root.as_ref()?; + let git_repo = Repository::open(repo_root).ok()?; + let is_detached = git_repo.head_detached().ok()?; + if config.only_attached && is_detached { + return None; + }; + let branch_name = repo.branch.as_ref()?; let mut graphemes: Vec<&str> = branch_name.graphemes(true).collect(); @@ -246,6 +255,57 @@ mod tests { repo_dir.close() } + #[test] + fn test_render_branch_only_attached_on_branch() -> io::Result<()> { + let repo_dir = fixture_repo(FixtureProvider::GIT)?; + + Command::new("git") + .args(&["checkout", "-b", "test_branch"]) + .current_dir(repo_dir.path()) + .output()?; + + let actual = ModuleRenderer::new("git_branch") + .config(toml::toml! { + [git_branch] + only_attached = true + }) + .path(&repo_dir.path()) + .collect(); + + let expected = Some(format!( + "on {} ", + Color::Purple + .bold() + .paint(format!("\u{e0a0} {}", "test_branch")), + )); + + assert_eq!(expected, actual); + repo_dir.close() + } + + #[test] + fn test_render_branch_only_attached_on_detached() -> io::Result<()> { + let repo_dir = fixture_repo(FixtureProvider::GIT)?; + + Command::new("git") + .args(&["checkout", "@~1"]) + .current_dir(&repo_dir.path()) + .output()?; + + let actual = ModuleRenderer::new("git_branch") + .config(toml::toml! { + [git_branch] + only_attached = true + }) + .path(&repo_dir.path()) + .collect(); + + let expected = None; + + assert_eq!(expected, actual); + repo_dir.close() + } + // This test is not possible until we switch to `git status --porcelain` // where we can mock the env for the specific git process. This is because // git2 does not care about our mocking and when we set the real `GIT_DIR`