From e90cf0b9412b7f8fcb557d1edb2c3f586c7bd45b Mon Sep 17 00:00:00 2001 From: Smit Barmase Date: Wed, 23 Jul 2025 06:46:24 +0530 Subject: [PATCH] workspace: Fix last removed folder from workspace used to reopen on Zed startup (#34925) Closes #34924 Now, when `local_paths` are empty, we detach `session_id` from that workspace serialization item. This way, when we restore it using the default "last_session", we don't restore this workspace back. This is same as when we use `cmd-w` to close window, which also sets `session_id` to `None` before serialization. Release Notes: - Fixed an issue where last removed folder from workspace used to reopen on Zed startup. --- crates/workspace/src/persistence.rs | 8 +++ crates/workspace/src/workspace.rs | 87 ++++++++++++++++++----------- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 406f37419d1b02d14817ad165d4fa5cdd4c6d452..3f8b098203e4fcf82e740cffc4e0de06d170a34e 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -1336,6 +1336,14 @@ impl WorkspaceDb { } } + query! { + pub(crate) async fn set_session_id(workspace_id: WorkspaceId, session_id: Option) -> Result<()> { + UPDATE workspaces + SET session_id = ?2 + WHERE workspace_id = ?1 + } + } + pub async fn toolchain( &self, workspace_id: WorkspaceId, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f37abe59e24b64cc8a7e4f699afb1e3cc569a42f..2c223c476bcdf6872d24dd5f596b88c511c7a5b0 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1016,6 +1016,15 @@ pub enum OpenVisible { OnlyDirectories, } +enum WorkspaceLocation { + // Valid local paths or SSH project to serialize + Location(SerializedWorkspaceLocation), + // No valid location found hence clear session id + DetachFromSession, + // No valid location found to serialize + None, +} + type PromptForNewPath = Box< dyn Fn( &mut Workspace, @@ -1135,7 +1144,6 @@ impl Workspace { this.update_window_title(window, cx); this.serialize_workspace(window, cx); // This event could be triggered by `AddFolderToProject` or `RemoveFromProject`. - // So we need to update the history. this.update_history(cx); } @@ -5218,48 +5226,58 @@ impl Workspace { } } - if let Some(location) = self.serialize_workspace_location(cx) { - let breakpoints = self.project.update(cx, |project, cx| { - project - .breakpoint_store() - .read(cx) - .all_source_breakpoints(cx) - }); + match self.serialize_workspace_location(cx) { + WorkspaceLocation::Location(location) => { + let breakpoints = self.project.update(cx, |project, cx| { + project + .breakpoint_store() + .read(cx) + .all_source_breakpoints(cx) + }); - let center_group = build_serialized_pane_group(&self.center.root, window, cx); - let docks = build_serialized_docks(self, window, cx); - let window_bounds = Some(SerializedWindowBounds(window.window_bounds())); - let serialized_workspace = SerializedWorkspace { - id: database_id, - location, - center_group, - window_bounds, - display: Default::default(), - docks, - centered_layout: self.centered_layout, - session_id: self.session_id.clone(), - breakpoints, - window_id: Some(window.window_handle().window_id().as_u64()), - }; + let center_group = build_serialized_pane_group(&self.center.root, window, cx); + let docks = build_serialized_docks(self, window, cx); + let window_bounds = Some(SerializedWindowBounds(window.window_bounds())); + let serialized_workspace = SerializedWorkspace { + id: database_id, + location, + center_group, + window_bounds, + display: Default::default(), + docks, + centered_layout: self.centered_layout, + session_id: self.session_id.clone(), + breakpoints, + window_id: Some(window.window_handle().window_id().as_u64()), + }; - return window.spawn(cx, async move |_| { - persistence::DB.save_workspace(serialized_workspace).await; - }); + window.spawn(cx, async move |_| { + persistence::DB.save_workspace(serialized_workspace).await; + }) + } + WorkspaceLocation::DetachFromSession => window.spawn(cx, async move |_| { + persistence::DB + .set_session_id(database_id, None) + .await + .log_err(); + }), + WorkspaceLocation::None => Task::ready(()), } - Task::ready(()) } - fn serialize_workspace_location(&self, cx: &App) -> Option { + fn serialize_workspace_location(&self, cx: &App) -> WorkspaceLocation { if let Some(ssh_project) = &self.serialized_ssh_project { - Some(SerializedWorkspaceLocation::Ssh(ssh_project.clone())) + WorkspaceLocation::Location(SerializedWorkspaceLocation::Ssh(ssh_project.clone())) } else if let Some(local_paths) = self.local_paths(cx) { if !local_paths.is_empty() { - Some(SerializedWorkspaceLocation::from_local_paths(local_paths)) + WorkspaceLocation::Location(SerializedWorkspaceLocation::from_local_paths( + local_paths, + )) } else { - None + WorkspaceLocation::DetachFromSession } } else { - None + WorkspaceLocation::None } } @@ -5267,8 +5285,9 @@ impl Workspace { let Some(id) = self.database_id() else { return; }; - let Some(location) = self.serialize_workspace_location(cx) else { - return; + let location = match self.serialize_workspace_location(cx) { + WorkspaceLocation::Location(location) => location, + _ => return, }; if let Some(manager) = HistoryManager::global(cx) { manager.update(cx, |this, cx| {