Allow opening a new window for secondary worktrees
Previously, running `zed foo` when `foo` was already open as a worktree in an existing window would reuse that window, even if `foo` was not the primary worktree. This made it impossible to open a dedicated window for a directory that was already added as a secondary worktree elsewhere. Now, we only reuse an existing window if the path matches its primary worktree (the first visible worktree, typically the directory originally opened to create that window). This allows users to run `zed foo` and get a new window where `foo` is the primary worktree, even if `foo` is already open as a secondary worktree in another window.
This commit is contained in:
@@ -7574,7 +7574,6 @@ pub fn open_paths(
|
||||
> {
|
||||
let abs_paths = abs_paths.to_vec();
|
||||
let mut existing = None;
|
||||
let mut best_match = None;
|
||||
let mut open_visible = OpenVisible::All;
|
||||
#[cfg(target_os = "windows")]
|
||||
let wsl_path = abs_paths
|
||||
@@ -7593,16 +7592,23 @@ pub fn open_paths(
|
||||
cx.update(|cx| {
|
||||
for window in local_workspace_windows(cx) {
|
||||
if let Ok(workspace) = window.read(cx) {
|
||||
let m = workspace.project.read(cx).visibility_for_paths(
|
||||
&abs_paths,
|
||||
&all_metadatas,
|
||||
open_options.open_new_workspace == None,
|
||||
cx,
|
||||
);
|
||||
if m > best_match {
|
||||
// Only reuse an existing window if the paths match its primary worktree
|
||||
// (the first visible worktree, typically the directory originally opened).
|
||||
// This allows `zed foo` to open a new window even if `foo` is already
|
||||
// open as a secondary worktree in another window.
|
||||
let dominated_by_this_window = workspace
|
||||
.project
|
||||
.read(cx)
|
||||
.visible_worktrees(cx)
|
||||
.next()
|
||||
.and_then(|w| w.read(cx).as_local().map(|w| w.abs_path()))
|
||||
.is_some_and(|primary_path| {
|
||||
abs_paths.iter().any(|path| path.starts_with(&primary_path))
|
||||
});
|
||||
if dominated_by_this_window {
|
||||
existing = Some(window);
|
||||
best_match = m;
|
||||
} else if best_match.is_none()
|
||||
break;
|
||||
} else if existing.is_none()
|
||||
&& open_options.open_new_workspace == Some(false)
|
||||
{
|
||||
existing = Some(window)
|
||||
|
||||
@@ -753,6 +753,85 @@ mod tests {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_secondary_worktree_in_new_window(cx: &mut TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"dir1": {
|
||||
"file1.txt": "content1",
|
||||
},
|
||||
"dir2": {
|
||||
"file2.txt": "content2",
|
||||
},
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(cx.windows().len(), 0);
|
||||
|
||||
// Open dir1 as the first worktree
|
||||
open_workspace_file(path!("/root/dir1"), None, app_state.clone(), cx).await;
|
||||
|
||||
assert_eq!(cx.windows().len(), 1);
|
||||
let workspace_1 = cx.windows()[0].downcast::<Workspace>().unwrap();
|
||||
|
||||
// Add dir2 as a secondary worktree to the same window
|
||||
workspace_1
|
||||
.update(cx, |workspace, _, cx| {
|
||||
workspace.project().update(cx, |project, cx| {
|
||||
project.find_or_create_worktree(path!("/root/dir2"), true, cx)
|
||||
})
|
||||
})
|
||||
.unwrap()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Verify both worktrees are in the same window
|
||||
workspace_1
|
||||
.update(cx, |workspace, _, cx| {
|
||||
let worktrees: Vec<_> = workspace.worktrees(cx).collect();
|
||||
assert_eq!(worktrees.len(), 2, "Should have two worktrees");
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(cx.windows().len(), 1);
|
||||
|
||||
// Now open dir2 via CLI - this should open a NEW window since dir2 is not
|
||||
// the first worktree of the existing window
|
||||
open_workspace_file(path!("/root/dir2"), None, app_state.clone(), cx).await;
|
||||
|
||||
assert_eq!(
|
||||
cx.windows().len(),
|
||||
2,
|
||||
"Opening a secondary worktree should create a new window"
|
||||
);
|
||||
|
||||
// Verify the new window has dir2 as its first (and only) worktree
|
||||
let workspace_2 = cx.windows()[1].downcast::<Workspace>().unwrap();
|
||||
workspace_2
|
||||
.update(cx, |workspace, _, cx| {
|
||||
let worktrees: Vec<_> = workspace.worktrees(cx).collect();
|
||||
assert_eq!(worktrees.len(), 1, "New window should have one worktree");
|
||||
assert_eq!(worktrees[0].read(cx).root_name(), "dir2");
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Opening dir1 should still reuse the first window since it's the first worktree there
|
||||
open_workspace_file(path!("/root/dir1/file1.txt"), None, app_state.clone(), cx).await;
|
||||
|
||||
assert_eq!(
|
||||
cx.windows().len(),
|
||||
2,
|
||||
"Opening a file in the first worktree should reuse the existing window"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_workspace_with_nonexistent_files(cx: &mut TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
|
||||
Reference in New Issue
Block a user