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.
This commit is contained in:
Smit Barmase 2025-07-23 06:46:24 +05:30 committed by GitHub
parent 056003860a
commit e90cf0b941
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 61 additions and 34 deletions

View file

@ -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<SerializedWorkspaceLocation> {
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| {