Detailed changes
@@ -22,7 +22,7 @@ use util::ResultExt;
use workspace::notifications::DetachAndPromptErr;
use workspace::{ModalView, Workspace};
-use crate::{branch_picker, git_panel::show_error_toast, resolve_active_repository};
+use crate::{branch_picker, git_panel::show_error_toast};
actions!(
branch_picker,
@@ -59,7 +59,7 @@ pub fn open(
cx: &mut Context<Workspace>,
) {
let workspace_handle = workspace.weak_handle();
- let repository = resolve_active_repository(workspace, cx);
+ let repository = workspace.project().read(cx).active_repository(cx);
workspace.toggle_modal(window, cx, |window, cx| {
BranchList::new(
@@ -582,7 +582,7 @@ fn open_with_tab(
cx: &mut Context<Workspace>,
) {
let workspace_handle = workspace.weak_handle();
- let repository = crate::resolve_active_repository(workspace, cx);
+ let repository = workspace.project().read(cx).active_repository(cx);
workspace.toggle_modal(window, cx, |window, cx| {
GitPicker::new(workspace_handle, repository, tab, rems(34.), window, cx)
@@ -281,33 +281,6 @@ fn open_modified_files(
}
}
-/// Resolves the repository for git operations, respecting the workspace's
-/// active worktree override from the project dropdown.
-pub fn resolve_active_repository(workspace: &Workspace, cx: &App) -> Option<Entity<Repository>> {
- let project = workspace.project().read(cx);
- workspace
- .active_worktree_override()
- .and_then(|override_id| {
- project
- .worktree_for_id(override_id, cx)
- .and_then(|worktree| {
- let worktree_abs_path = worktree.read(cx).abs_path();
- let git_store = project.git_store().read(cx);
- git_store
- .repositories()
- .values()
- .filter(|repo| {
- let repo_path = &repo.read(cx).work_directory_abs_path;
- *repo_path == worktree_abs_path
- || worktree_abs_path.starts_with(repo_path.as_ref())
- })
- .max_by_key(|repo| repo.read(cx).work_directory_abs_path.as_os_str().len())
- .cloned()
- })
- })
- .or_else(|| project.active_repository(cx))
-}
-
pub fn git_status_icon(status: FileStatus) -> impl IntoElement {
GitStatusIcon::new(status)
}
@@ -2,7 +2,6 @@ use crate::{
conflict_view::ConflictAddon,
git_panel::{GitPanel, GitPanelAddon, GitStatusEntry},
git_panel_settings::GitPanelSettings,
- resolve_active_repository,
};
use agent_settings::AgentSettings;
use anyhow::{Context as _, Result, anyhow};
@@ -205,7 +204,7 @@ impl ProjectDiff {
"Action"
}
);
- let intended_repo = resolve_active_repository(workspace, cx);
+ let intended_repo = workspace.project().read(cx).active_repository(cx);
let existing = workspace
.items_of_type::<Self>(cx)
@@ -2708,7 +2707,7 @@ mod tests {
}
#[gpui::test]
- async fn test_deploy_at_respects_worktree_override(cx: &mut TestAppContext) {
+ async fn test_deploy_at_respects_active_repository_selection(cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
@@ -2759,9 +2758,12 @@ mod tests {
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
cx.run_until_parked();
- // Select project A via the dropdown override and open the diff.
+ // Select project A explicitly and open the diff.
workspace.update(cx, |workspace, cx| {
- workspace.set_active_worktree_override(Some(worktree_a_id), cx);
+ let git_store = workspace.project().read(cx).git_store().clone();
+ git_store.update(cx, |git_store, cx| {
+ git_store.set_active_repo_for_worktree(worktree_a_id, cx);
+ });
});
cx.focus(&workspace);
cx.update(|window, cx| {
@@ -2776,9 +2778,12 @@ mod tests {
assert_eq!(paths_a.len(), 1);
assert_eq!(*paths_a[0], *"a.txt");
- // Switch the override to project B and re-run the diff action.
+ // Switch the explicit active repository to project B and re-run the diff action.
workspace.update(cx, |workspace, cx| {
- workspace.set_active_worktree_override(Some(worktree_b_id), cx);
+ let git_store = workspace.project().read(cx).git_store().clone();
+ git_store.update(cx, |git_store, cx| {
+ git_store.set_active_repo_for_worktree(worktree_b_id, cx);
+ });
});
cx.focus(&workspace);
cx.update(|window, cx| {
@@ -594,16 +594,49 @@ impl GitStore {
pub fn is_local(&self) -> bool {
matches!(self.state, GitStoreState::Local { .. })
}
+
+ fn set_active_repo_id(&mut self, repo_id: RepositoryId, cx: &mut Context<Self>) {
+ if self.active_repo_id != Some(repo_id) {
+ self.active_repo_id = Some(repo_id);
+ cx.emit(GitStoreEvent::ActiveRepositoryChanged(Some(repo_id)));
+ }
+ }
+
pub fn set_active_repo_for_path(&mut self, project_path: &ProjectPath, cx: &mut Context<Self>) {
if let Some((repo, _)) = self.repository_and_path_for_project_path(project_path, cx) {
- let id = repo.read(cx).id;
- if self.active_repo_id != Some(id) {
- self.active_repo_id = Some(id);
- cx.emit(GitStoreEvent::ActiveRepositoryChanged(Some(id)));
- }
+ self.set_active_repo_id(repo.read(cx).id, cx);
}
}
+ pub fn set_active_repo_for_worktree(
+ &mut self,
+ worktree_id: WorktreeId,
+ cx: &mut Context<Self>,
+ ) {
+ let Some(worktree) = self
+ .worktree_store
+ .read(cx)
+ .worktree_for_id(worktree_id, cx)
+ else {
+ return;
+ };
+ let worktree_abs_path = worktree.read(cx).abs_path();
+ let Some(repo_id) = self
+ .repositories
+ .values()
+ .filter(|repo| {
+ let repo_path = &repo.read(cx).work_directory_abs_path;
+ *repo_path == worktree_abs_path || worktree_abs_path.starts_with(repo_path.as_ref())
+ })
+ .max_by_key(|repo| repo.read(cx).work_directory_abs_path.as_os_str().len())
+ .map(|repo| repo.read(cx).id)
+ else {
+ return;
+ };
+
+ self.set_active_repo_id(repo_id, cx);
+ }
+
pub fn shared(&mut self, project_id: u64, client: AnyProtoClient, cx: &mut Context<Self>) {
match &mut self.state {
GitStoreState::Remote {
@@ -168,22 +168,20 @@ fn get_open_folders(workspace: &Workspace, cx: &App) -> Vec<OpenFolderEntry> {
return Vec::new();
}
- let active_worktree_id = workspace.active_worktree_override().or_else(|| {
- if let Some(repo) = project.active_repository(cx) {
- let repo = repo.read(cx);
- let repo_path = &repo.work_directory_abs_path;
- for worktree in project.visible_worktrees(cx) {
- let worktree_path = worktree.read(cx).abs_path();
- if worktree_path == *repo_path || worktree_path.starts_with(repo_path.as_ref()) {
- return Some(worktree.read(cx).id());
- }
- }
- }
+ let active_worktree_id = if let Some(repo) = project.active_repository(cx) {
+ let repo = repo.read(cx);
+ let repo_path = &repo.work_directory_abs_path;
+ project.visible_worktrees(cx).find_map(|worktree| {
+ let worktree_path = worktree.read(cx).abs_path();
+ (worktree_path == *repo_path || worktree_path.starts_with(repo_path.as_ref()))
+ .then(|| worktree.read(cx).id())
+ })
+ } else {
project
.visible_worktrees(cx)
.next()
.map(|wt| wt.read(cx).id())
- });
+ };
let mut all_paths: Vec<PathBuf> = visible_worktrees
.iter()
@@ -1118,7 +1116,10 @@ impl PickerDelegate for RecentProjectsDelegate {
let worktree_id = folder.worktree_id;
if let Some(workspace) = self.workspace.upgrade() {
workspace.update(cx, |workspace, cx| {
- workspace.set_active_worktree_override(Some(worktree_id), cx);
+ let git_store = workspace.project().read(cx).git_store().clone();
+ git_store.update(cx, |git_store, cx| {
+ git_store.set_active_repo_for_worktree(worktree_id, cx);
+ });
});
}
cx.emit(DismissEvent);
@@ -33,7 +33,6 @@ use onboarding_banner::OnboardingBanner;
use project::{Project, git_store::GitStoreEvent, trusted_worktrees::TrustedWorktrees};
use remote::RemoteConnectionOptions;
use settings::Settings;
-use settings::WorktreeId;
use std::sync::Arc;
use std::time::Duration;
@@ -377,27 +376,13 @@ impl TitleBar {
cx.notify()
}),
);
- subscriptions.push(
- cx.subscribe(&project, |this, _, event: &project::Event, cx| {
- if let project::Event::BufferEdited = event {
- // Clear override when user types in any editor,
- // so the title bar reflects the project they're actually working in
- this.clear_active_worktree_override(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 |this, _, event, cx| match event {
- GitStoreEvent::ActiveRepositoryChanged(_) => {
- // Clear override when focus-derived active repo changes
- // (meaning the user focused a file from a different project)
- this.clear_active_worktree_override(cx);
- cx.notify();
- }
- GitStoreEvent::RepositoryUpdated(_, _, true) => {
+ cx.subscribe(&git_store, move |_, _, event, cx| match event {
+ GitStoreEvent::ActiveRepositoryChanged(_)
+ | GitStoreEvent::RepositoryUpdated(_, _, true) => {
cx.notify();
}
_ => {}
@@ -451,20 +436,11 @@ impl TitleBar {
}
/// Returns the worktree to display in the title bar.
- /// - If there's an override set on the workspace, use that (if still valid)
- /// - Otherwise, derive from the active repository
+ /// - Prefer the worktree owning the project's active repository
/// - Fall back to the first visible worktree
pub fn effective_active_worktree(&self, cx: &App) -> Option<Entity<project::Worktree>> {
let project = self.project.read(cx);
- if let Some(workspace) = self.workspace.upgrade() {
- if let Some(override_id) = workspace.read(cx).active_worktree_override() {
- if let Some(worktree) = project.worktree_for_id(override_id, cx) {
- return Some(worktree);
- }
- }
- }
-
if let Some(repo) = project.active_repository(cx) {
let repo = repo.read(cx);
let repo_path = &repo.work_directory_abs_path;
@@ -480,28 +456,6 @@ impl TitleBar {
project.visible_worktrees(cx).next()
}
- pub fn set_active_worktree_override(
- &mut self,
- worktree_id: WorktreeId,
- cx: &mut Context<Self>,
- ) {
- if let Some(workspace) = self.workspace.upgrade() {
- workspace.update(cx, |workspace, cx| {
- workspace.set_active_worktree_override(Some(worktree_id), cx);
- });
- }
- cx.notify();
- }
-
- fn clear_active_worktree_override(&mut self, cx: &mut Context<Self>) {
- if let Some(workspace) = self.workspace.upgrade() {
- workspace.update(cx, |workspace, cx| {
- workspace.clear_active_worktree_override(cx);
- });
- }
- cx.notify();
- }
-
fn get_repository_for_worktree(
&self,
worktree: &Entity<project::Worktree>,
@@ -1325,7 +1325,6 @@ pub struct Workspace {
bottom_dock: Entity<Dock>,
right_dock: Entity<Dock>,
panes: Vec<Entity<Pane>>,
- active_worktree_override: Option<WorktreeId>,
panes_by_item: HashMap<EntityId, WeakEntity<Pane>>,
active_pane: Entity<Pane>,
last_active_center_pane: Option<WeakEntity<Pane>>,
@@ -1758,7 +1757,6 @@ impl Workspace {
modal_layer,
toast_layer,
titlebar_item: None,
- active_worktree_override: None,
notifications: Notifications::default(),
suppressed_notifications: HashSet::default(),
left_dock,
@@ -2951,27 +2949,6 @@ impl Workspace {
self.titlebar_item.clone()
}
- /// Returns the worktree override set by the user (e.g., via the project dropdown).
- /// When set, git-related operations should use this worktree instead of deriving
- /// the active worktree from the focused file.
- pub fn active_worktree_override(&self) -> Option<WorktreeId> {
- self.active_worktree_override
- }
-
- pub fn set_active_worktree_override(
- &mut self,
- worktree_id: Option<WorktreeId>,
- cx: &mut Context<Self>,
- ) {
- self.active_worktree_override = worktree_id;
- cx.notify();
- }
-
- pub fn clear_active_worktree_override(&mut self, cx: &mut Context<Self>) {
- self.active_worktree_override = None;
- cx.notify();
- }
-
/// Call the given callback with a workspace whose project is local or remote via WSL (allowing host access).
///
/// If the given workspace has a local project, then it will be passed