From 3707102702905185b1d08e09456523b10a27e007 Mon Sep 17 00:00:00 2001 From: Lev Zakharov Date: Mon, 6 Oct 2025 16:43:22 +0300 Subject: [PATCH] title_bar: Show git status indicator icon in the title bar (#38029) See related discussion #37046.
Screenshots **No Changes** **Added** **Changed** **Deleted** **Conflicts**
Release Notes: - Show git status indicator icon in the title bar --- crates/title_bar/src/title_bar.rs | 80 +++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index 5673e3c26e672030764cd02309a8189966be40ba..b855e8132a1a0c83b827318e1cf675f684b49a3a 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -30,7 +30,10 @@ use gpui::{ Subscription, WeakEntity, Window, actions, div, }; use onboarding_banner::OnboardingBanner; -use project::{Project, WorktreeSettings}; +use project::{ + Project, WorktreeSettings, + git_store::{GitStoreEvent, RepositoryEvent}, +}; use remote::RemoteConnectionOptions; use settings::{Settings, SettingsLocation}; use std::sync::Arc; @@ -245,6 +248,7 @@ impl TitleBar { cx: &mut Context, ) -> Self { let project = workspace.project().clone(); + let git_store = project.read(cx).git_store().clone(); let user_store = workspace.app_state().user_store.clone(); let client = workspace.app_state().client.clone(); let active_call = ActiveCall::global(cx); @@ -272,6 +276,17 @@ impl TitleBar { subscriptions.push(cx.subscribe(&project, |_, _, _: &project::Event, cx| cx.notify())); subscriptions.push(cx.observe(&active_call, |this, _, cx| this.active_call_changed(cx))); subscriptions.push(cx.observe_window_activation(window, Self::window_activation_changed)); + subscriptions.push( + cx.subscribe(&git_store, move |_, _, event, cx| match event { + GitStoreEvent::ActiveRepositoryChanged(_) + | GitStoreEvent::RepositoryUpdated(_, RepositoryEvent::Updated { .. }, _) + | GitStoreEvent::RepositoryAdded(_) + | GitStoreEvent::RepositoryRemoved(_) => { + cx.notify(); + } + _ => {} + }), + ); subscriptions.push(cx.observe(&user_store, |_, _, cx| cx.notify())); let banner = cx.new(|cx| { @@ -480,24 +495,24 @@ impl TitleBar { } pub fn render_project_branch(&self, cx: &mut Context) -> Option { + let settings = TitleBarSettings::get_global(cx); let repository = self.project.read(cx).active_repository(cx)?; let workspace = self.workspace.upgrade()?; - let branch_name = { - let repo = repository.read(cx); - repo.branch - .as_ref() - .map(|branch| branch.name()) - .map(|name| util::truncate_and_trailoff(name, MAX_BRANCH_NAME_LENGTH)) - .or_else(|| { - repo.head_commit.as_ref().map(|commit| { - commit - .sha - .chars() - .take(MAX_SHORT_SHA_LENGTH) - .collect::() - }) + let repo = repository.read(cx); + let branch_name = repo + .branch + .as_ref() + .map(|branch| branch.name()) + .map(|name| util::truncate_and_trailoff(name, MAX_BRANCH_NAME_LENGTH)) + .or_else(|| { + repo.head_commit.as_ref().map(|commit| { + commit + .sha + .chars() + .take(MAX_SHORT_SHA_LENGTH) + .collect::() }) - }?; + })?; Some( Button::new("project_branch_trigger", branch_name) @@ -519,16 +534,29 @@ impl TitleBar { window.dispatch_action(zed_actions::git::Branch.boxed_clone(), cx); }); }) - .when( - TitleBarSettings::get_global(cx).show_branch_icon, - |branch_button| { - branch_button - .icon(IconName::GitBranch) - .icon_position(IconPosition::Start) - .icon_color(Color::Muted) - .icon_size(IconSize::Indicator) - }, - ), + .when(settings.show_branch_icon, |branch_button| { + let (icon, icon_color) = { + let status = repo.status_summary(); + let tracked = status.index + status.worktree; + if status.conflict > 0 { + (IconName::Warning, Color::VersionControlConflict) + } else if tracked.modified > 0 { + (IconName::SquareDot, Color::VersionControlModified) + } else if tracked.added > 0 || status.untracked > 0 { + (IconName::SquarePlus, Color::VersionControlAdded) + } else if tracked.deleted > 0 { + (IconName::SquareMinus, Color::VersionControlDeleted) + } else { + (IconName::GitBranch, Color::Muted) + } + }; + + branch_button + .icon(icon) + .icon_position(IconPosition::Start) + .icon_color(icon_color) + .icon_size(IconSize::Indicator) + }), ) }