Make zed foo/ add to active window and open sidebar (#53254)
Changes the default CLI behavior when opening directories: - `zed foo/` now adds `foo/` as a new workspace in the active window's MultiWorkspace and opens the sidebar, instead of creating a new window. If `bar/` was previously open, both `foo/` and `bar/` are retained as separate workspaces in the sidebar. - `zed -n foo/` continues to open a new window without the sidebar (unchanged behavior). - `zed -a foo/` continues to add to the existing workspace (unchanged behavior). The new behavior is gated on `multi_workspace_enabled` (the `agent-v2` feature flag). Without the flag, directories open in a new window as before, avoiding a situation where the workspace gets replaced with no sidebar to switch back. The change is contained to `open_paths()` in `crates/workspace/src/workspace.rs`. When no CLI flag is specified and no existing workspace matches the paths, we now look for the active window and set `requesting_window` so that `Workspace::new_local` adds the new workspace to it rather than creating a new window. Release Notes: - N/A
This commit is contained in:
1 parent
7748047051
commit
d22f8bf2a7
2 files changed
+62
-37
No files matched your search
@@ -9325,7 +9325,7 @@ pub fn open_workspace_by_id(
|
||||
pub fn open_paths(
|
||||
abs_paths: &[PathBuf],
|
||||
app_state: Arc<AppState>,
|
||||
open_options: OpenOptions,
|
||||
mut open_options: OpenOptions,
|
||||
cx: &mut App,
|
||||
) -> Task<anyhow::Result<OpenResult>> {
|
||||
let abs_paths = abs_paths.to_vec();
|
||||
@@ -9350,10 +9350,9 @@ pub fn open_paths(
|
||||
let all_metadatas = futures::future::join_all(all_paths)
|
||||
.await
|
||||
.into_iter()
|
||||
.filter_map(|result| result.ok().flatten())
|
||||
.collect::<Vec<_>>();
|
||||
.filter_map(|result| result.ok().flatten());
|
||||
|
||||
if all_metadatas.iter().all(|file| !file.is_dir) {
|
||||
if all_metadatas.into_iter().all(|file| !file.is_dir) {
|
||||
cx.update(|cx| {
|
||||
let windows = workspace_windows_for_location(
|
||||
&SerializedWorkspaceLocation::Local,
|
||||
@@ -9375,6 +9374,35 @@ pub fn open_paths(
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback for directories: when no flag is specified and no existing
|
||||
// workspace matched, add the directory as a new workspace in the
|
||||
// active window's MultiWorkspace (instead of opening a new window).
|
||||
if open_options.open_new_workspace.is_none() && existing.is_none() {
|
||||
let target_window = cx.update(|cx| {
|
||||
let windows = workspace_windows_for_location(
|
||||
&SerializedWorkspaceLocation::Local,
|
||||
cx,
|
||||
);
|
||||
let window = cx
|
||||
.active_window()
|
||||
.and_then(|window| window.downcast::<MultiWorkspace>())
|
||||
.filter(|window| windows.contains(window))
|
||||
.or_else(|| windows.into_iter().next());
|
||||
window.filter(|window| {
|
||||
window.read(cx).is_ok_and(|mw| mw.multi_workspace_enabled(cx))
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(window) = target_window {
|
||||
open_options.requesting_window = Some(window);
|
||||
window
|
||||
.update(cx, |multi_workspace, _, cx| {
|
||||
multi_workspace.open_sidebar(cx);
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
|
||||
let open_in_dev_container = open_options.open_in_dev_container;
|
||||
|
||||
let result = if let Some((existing, target_workspace)) = existing {
|
||||
|
||||
+30
-33
@@ -2606,18 +2606,33 @@ mod tests {
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(cx.read(|cx| cx.windows().len()), 2);
|
||||
|
||||
// Replace existing windows
|
||||
let window = cx
|
||||
.update(|cx| cx.windows()[0].downcast::<MultiWorkspace>())
|
||||
assert_eq!(cx.read(|cx| cx.windows().len()), 1);
|
||||
cx.run_until_parked();
|
||||
multi_workspace_1
|
||||
.update(cx, |multi_workspace, _window, cx| {
|
||||
assert_eq!(multi_workspace.workspaces().len(), 2);
|
||||
assert!(multi_workspace.sidebar_open());
|
||||
let workspace = multi_workspace.workspace().read(cx);
|
||||
assert_eq!(
|
||||
workspace
|
||||
.worktrees(cx)
|
||||
.map(|w| w.read(cx).abs_path())
|
||||
.collect::<Vec<_>>(),
|
||||
&[
|
||||
Path::new(path!("/root/c")).into(),
|
||||
Path::new(path!("/root/d")).into(),
|
||||
]
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Opening with -n (open_new_workspace: Some(true)) still creates a new window.
|
||||
cx.update(|cx| {
|
||||
open_paths(
|
||||
&[PathBuf::from(path!("/root/e"))],
|
||||
app_state,
|
||||
workspace::OpenOptions {
|
||||
requesting_window: Some(window),
|
||||
open_new_workspace: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
@@ -2627,23 +2642,6 @@ mod tests {
|
||||
.unwrap();
|
||||
cx.background_executor.run_until_parked();
|
||||
assert_eq!(cx.read(|cx| cx.windows().len()), 2);
|
||||
let multi_workspace_1 = cx
|
||||
.update(|cx| cx.windows()[0].downcast::<MultiWorkspace>())
|
||||
.unwrap();
|
||||
multi_workspace_1
|
||||
.update(cx, |multi_workspace, window, cx| {
|
||||
let workspace = multi_workspace.workspace().read(cx);
|
||||
assert_eq!(
|
||||
workspace
|
||||
.worktrees(cx)
|
||||
.map(|w| w.read(cx).abs_path())
|
||||
.collect::<Vec<_>>(),
|
||||
&[Path::new(path!("/root/e")).into()]
|
||||
);
|
||||
assert!(workspace.right_dock().read(cx).is_open());
|
||||
assert!(workspace.active_pane().focus_handle(cx).is_focused(window));
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
@@ -2724,7 +2722,6 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(cx.update(|cx| cx.windows().len()), 1);
|
||||
let window1 = cx.update(|cx| cx.active_window().unwrap());
|
||||
|
||||
cx.update(|cx| {
|
||||
open_paths(
|
||||
@@ -2738,6 +2735,8 @@ mod tests {
|
||||
.unwrap();
|
||||
assert_eq!(cx.update(|cx| cx.windows().len()), 1);
|
||||
|
||||
// Opening a directory with default options adds to the existing window
|
||||
// rather than creating a new one.
|
||||
cx.update(|cx| {
|
||||
open_paths(
|
||||
&[PathBuf::from(path!("/root/dir2"))],
|
||||
@@ -2748,25 +2747,23 @@ mod tests {
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(cx.update(|cx| cx.windows().len()), 2);
|
||||
let window2 = cx.update(|cx| cx.active_window().unwrap());
|
||||
assert!(window1 != window2);
|
||||
cx.update_window(window1, |_, window, _| window.activate_window())
|
||||
.unwrap();
|
||||
assert_eq!(cx.update(|cx| cx.windows().len()), 1);
|
||||
|
||||
// Opening a directory with -n creates a new window.
|
||||
cx.update(|cx| {
|
||||
open_paths(
|
||||
&[PathBuf::from(path!("/root/dir2/c"))],
|
||||
&[PathBuf::from(path!("/root/dir2"))],
|
||||
app_state.clone(),
|
||||
workspace::OpenOptions::default(),
|
||||
workspace::OpenOptions {
|
||||
open_new_workspace: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(cx.update(|cx| cx.windows().len()), 2);
|
||||
// should have opened in window2 because that has dir2 visibly open (window1 has it open, but not in the project panel)
|
||||
assert!(cx.update(|cx| cx.active_window().unwrap()) == window2);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
||||
Reference in new issue
Block a user