cli: Use --wait to prefer focused window (#41051)

Dino and Conrad Irwin created

Introduce a new `prefer_focused_window` field to the
`workspace::OpenOptions` struct that, when provided, will make it so
that Zed opens the provided path in the currently focused window.

This will now automatically be set to true when the `--wait` flag is
used with the CLI.

Closes #40551 

Release Notes:

- Improved the `--wait` flag in Zed's CLI so as to always open the
provided file in the currently focused window

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>

Change summary

crates/workspace/src/workspace.rs   |  3 +
crates/zed/src/zed.rs               | 59 +++++++++++++++++++++++++++++++
crates/zed/src/zed/open_listener.rs |  1 
3 files changed, 62 insertions(+), 1 deletion(-)

Detailed changes

crates/workspace/src/workspace.rs 🔗

@@ -7323,6 +7323,7 @@ pub struct OpenOptions {
     pub visible: Option<OpenVisible>,
     pub focus: Option<bool>,
     pub open_new_workspace: Option<bool>,
+    pub prefer_focused_window: bool,
     pub replace_window: Option<WindowHandle<Workspace>>,
     pub env: Option<HashMap<String, String>>,
 }
@@ -7379,7 +7380,7 @@ pub fn open_paths(
             })?;
 
             if open_options.open_new_workspace.is_none()
-                && existing.is_none()
+                && (existing.is_none() || open_options.prefer_focused_window)
                 && all_metadatas.iter().all(|file| !file.is_dir)
             {
                 cx.update(|cx| {

crates/zed/src/zed.rs 🔗

@@ -5086,4 +5086,63 @@ mod tests {
             "BUG FOUND: Project settings were overwritten when opening via command - original custom content was lost"
         );
     }
+
+    #[gpui::test]
+    async fn test_prefer_focused_window(cx: &mut gpui::TestAppContext) {
+        let app_state = init_test(cx);
+        let paths = [PathBuf::from(path!("/dir/document.txt"))];
+
+        app_state
+            .fs
+            .as_fake()
+            .insert_tree(
+                path!("/dir"),
+                json!({
+                    "document.txt": "Some of the documentation's content."
+                }),
+            )
+            .await;
+
+        let project_a = Project::test(app_state.fs.clone(), [path!("/dir").as_ref()], cx).await;
+        let window_a =
+            cx.add_window(|window, cx| Workspace::test_new(project_a.clone(), window, cx));
+
+        let project_b = Project::test(app_state.fs.clone(), [path!("/dir").as_ref()], cx).await;
+        let window_b =
+            cx.add_window(|window, cx| Workspace::test_new(project_b.clone(), window, cx));
+
+        let project_c = Project::test(app_state.fs.clone(), [path!("/dir").as_ref()], cx).await;
+        let window_c =
+            cx.add_window(|window, cx| Workspace::test_new(project_c.clone(), window, cx));
+
+        for window in [window_a, window_b, window_c] {
+            let _ = cx.update_window(*window, |_, window, _| {
+                window.activate_window();
+            });
+
+            cx.update(|cx| {
+                let open_options = OpenOptions {
+                    prefer_focused_window: true,
+                    ..Default::default()
+                };
+
+                workspace::open_paths(&paths, app_state.clone(), open_options, cx)
+            })
+            .await
+            .unwrap();
+
+            cx.update_window(*window, |_, window, _| assert!(window.is_window_active()))
+                .unwrap();
+
+            let _ = window.read_with(cx, |workspace, cx| {
+                let pane = workspace.active_pane().read(cx);
+                let project_path = pane.active_item().unwrap().project_path(cx).unwrap();
+
+                assert_eq!(
+                    project_path.path.as_ref().as_std_path().to_str().unwrap(),
+                    path!("document.txt")
+                )
+            });
+        }
+    }
 }

crates/zed/src/zed/open_listener.rs 🔗

@@ -531,6 +531,7 @@ async fn open_local_workspace(
         workspace::OpenOptions {
             open_new_workspace: effective_open_new_workspace,
             replace_window,
+            prefer_focused_window: wait,
             env: env.cloned(),
             ..Default::default()
         },