workspace: Add close project menu item (#47365)

Lukas Wirth created

cc https://github.com/zed-industries/zed/discussions/42163

Release Notes:

- Added a menu item to close the current project, going back to a clean
window state

Change summary

crates/workspace/src/workspace.rs |  4 ++
crates/zed/src/zed.rs             | 40 ++++++++++++++++++++++++++++++++
crates/zed/src/zed/app_menus.rs   |  1 
3 files changed, 43 insertions(+), 2 deletions(-)

Detailed changes

crates/workspace/src/workspace.rs 🔗

@@ -227,6 +227,8 @@ actions!(
         ToggleAllDocks,
         /// Closes the current window.
         CloseWindow,
+        /// Closes the current project.
+        CloseProject,
         /// Opens the feedback dialog.
         Feedback,
         /// Follows the next collaborator in the session.
@@ -8289,7 +8291,7 @@ pub fn open_new(
     let task = Workspace::new_local(
         Vec::new(),
         app_state,
-        None,
+        open_options.replace_window,
         open_options.env,
         Some(Box::new(init)),
         cx,

crates/zed/src/zed.rs 🔗

@@ -93,7 +93,8 @@ use workspace::{
     open_new,
 };
 use workspace::{
-    CloseIntent, CloseWindow, NotificationFrame, RestoreBanner, with_active_or_new_workspace,
+    CloseIntent, CloseProject, CloseWindow, NotificationFrame, RestoreBanner,
+    with_active_or_new_workspace,
 };
 use workspace::{Pane, notifications::DetachAndPromptErr};
 use zed_actions::{
@@ -1135,6 +1136,43 @@ fn register_actions(
                 }
             }
         })
+        .register_action({
+            let app_state = Arc::downgrade(&app_state);
+            move |_, _: &CloseProject, window, cx| {
+                let Some(window_handle) = window.window_handle().downcast::<Workspace>() else {
+                    return;
+                };
+                if let Some(app_state) = app_state.upgrade() {
+                    open_new(
+                        workspace::OpenOptions {
+                            replace_window: Some(window_handle),
+                            ..Default::default()
+                        },
+                        app_state,
+                        cx,
+                        |workspace, window, cx| {
+                            cx.activate(true);
+                            // Create buffer synchronously to avoid flicker
+                            let project = workspace.project().clone();
+                            let buffer = project.update(cx, |project, cx| {
+                                project.create_local_buffer("", None, true, cx)
+                            });
+                            let editor = cx.new(|cx| {
+                                Editor::for_buffer(buffer, Some(project), window, cx)
+                            });
+                            workspace.add_item_to_active_pane(
+                                Box::new(editor),
+                                None,
+                                true,
+                                window,
+                                cx,
+                            );
+                        },
+                    )
+                    .detach();
+                }
+            }
+        })
         .register_action({
             let app_state = Arc::downgrade(&app_state);
             move |_, _: &NewFile, _, cx| {

crates/zed/src/zed/app_menus.rs 🔗

@@ -154,6 +154,7 @@ pub fn app_menus(cx: &mut App) -> Vec<Menu> {
                         close_pinned: true,
                     },
                 ),
+                MenuItem::action("Close Project", workspace::CloseProject),
                 MenuItem::action("Close Window", workspace::CloseWindow),
             ],
         },