zed: Add ability to restore last session w/ multiple windows (#14965)
This adds the ability for Zed to restore multiple windows after
restarting. It's now the default behavior.
Release Notes:
- Added ability to restore all windows that were open when Zed was quit.
Previously only the last used workspace was restored. This is now the
default behavior. To get back the old behavior, add the following to
your settings: `{"restore_on_startup": "last_workspace"}` (Part of
[#4985](https://github.com/zed-industries/zed/issues/4985) and
[#4683](https://github.com/zed-industries/zed/issues/4683))
Demo:
https://github.com/user-attachments/assets/57a375ec-0c6a-4724-97c4-3fea8f18bc2d
---------
Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
@@ -170,6 +170,7 @@ define_connection! {
|
||||
// display: Option<Uuid>, // Display id
|
||||
// fullscreen: Option<bool>, // Is the window fullscreen?
|
||||
// centered_layout: Option<bool>, // Is the Centered Layout mode activated?
|
||||
// session_id: Option<String>, // Session id
|
||||
// )
|
||||
//
|
||||
// pane_groups(
|
||||
@@ -344,6 +345,9 @@ define_connection! {
|
||||
sql!(
|
||||
ALTER TABLE workspaces ADD COLUMN local_paths_order BLOB;
|
||||
),
|
||||
sql!(
|
||||
ALTER TABLE workspaces ADD COLUMN session_id TEXT DEFAULT NULL;
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -443,6 +447,7 @@ impl WorkspaceDb {
|
||||
centered_layout: centered_layout.unwrap_or(false),
|
||||
display,
|
||||
docks,
|
||||
session_id: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -536,6 +541,7 @@ impl WorkspaceDb {
|
||||
centered_layout: centered_layout.unwrap_or(false),
|
||||
display,
|
||||
docks,
|
||||
session_id: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -572,9 +578,10 @@ impl WorkspaceDb {
|
||||
bottom_dock_visible,
|
||||
bottom_dock_active_panel,
|
||||
bottom_dock_zoom,
|
||||
session_id,
|
||||
timestamp
|
||||
)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, CURRENT_TIMESTAMP)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT DO
|
||||
UPDATE SET
|
||||
local_paths = ?2,
|
||||
@@ -588,8 +595,9 @@ impl WorkspaceDb {
|
||||
bottom_dock_visible = ?10,
|
||||
bottom_dock_active_panel = ?11,
|
||||
bottom_dock_zoom = ?12,
|
||||
session_id = ?13,
|
||||
timestamp = CURRENT_TIMESTAMP
|
||||
))?((workspace.id, &local_paths, &local_paths_order, workspace.docks))
|
||||
))?((workspace.id, &local_paths, &local_paths_order, workspace.docks, workspace.session_id))
|
||||
.context("Updating workspace")?;
|
||||
}
|
||||
SerializedWorkspaceLocation::DevServer(dev_server_project) => {
|
||||
@@ -675,6 +683,15 @@ impl WorkspaceDb {
|
||||
}
|
||||
}
|
||||
|
||||
query! {
|
||||
fn session_workspace_locations(session_id: String) -> Result<Vec<LocalPaths>> {
|
||||
SELECT local_paths
|
||||
FROM workspaces
|
||||
WHERE session_id = ?1 AND dev_server_project_id IS NULL
|
||||
ORDER BY timestamp DESC
|
||||
}
|
||||
}
|
||||
|
||||
query! {
|
||||
fn dev_server_projects() -> Result<Vec<SerializedDevServerProject>> {
|
||||
SELECT id, path, dev_server_name
|
||||
@@ -770,6 +787,23 @@ impl WorkspaceDb {
|
||||
.next())
|
||||
}
|
||||
|
||||
pub fn last_session_workspace_locations(
|
||||
&self,
|
||||
last_session_id: &str,
|
||||
) -> Result<Vec<LocalPaths>> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for location in self.session_workspace_locations(last_session_id.to_owned())? {
|
||||
if location.paths().iter().all(|path| path.exists())
|
||||
&& location.paths().iter().any(|path| path.is_dir())
|
||||
{
|
||||
result.push(location);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn get_center_pane_group(&self, workspace_id: WorkspaceId) -> Result<SerializedPaneGroup> {
|
||||
Ok(self
|
||||
.get_pane_group(workspace_id, None)?
|
||||
@@ -983,6 +1017,7 @@ impl WorkspaceDb {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use db::open_test_db;
|
||||
use gpui;
|
||||
@@ -1065,6 +1100,7 @@ mod tests {
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: None,
|
||||
};
|
||||
|
||||
let workspace_2 = SerializedWorkspace {
|
||||
@@ -1075,6 +1111,7 @@ mod tests {
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: None,
|
||||
};
|
||||
|
||||
db.save_workspace(workspace_1.clone()).await;
|
||||
@@ -1177,6 +1214,7 @@ mod tests {
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: None,
|
||||
};
|
||||
|
||||
db.save_workspace(workspace.clone()).await;
|
||||
@@ -1209,6 +1247,7 @@ mod tests {
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: None,
|
||||
};
|
||||
|
||||
let mut workspace_2 = SerializedWorkspace {
|
||||
@@ -1219,6 +1258,7 @@ mod tests {
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: None,
|
||||
};
|
||||
|
||||
db.save_workspace(workspace_1.clone()).await;
|
||||
@@ -1259,6 +1299,7 @@ mod tests {
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: None,
|
||||
};
|
||||
|
||||
db.save_workspace(workspace_3.clone()).await;
|
||||
@@ -1279,6 +1320,75 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_session_workspace_locations() {
|
||||
env_logger::try_init().ok();
|
||||
|
||||
let db = WorkspaceDb(open_test_db("test_serializing_workspaces_session_id").await);
|
||||
|
||||
let workspace_1 = SerializedWorkspace {
|
||||
id: WorkspaceId(1),
|
||||
location: SerializedWorkspaceLocation::from_local_paths(["/tmp1"]),
|
||||
center_group: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: Some("session-id-1".to_owned()),
|
||||
};
|
||||
|
||||
let workspace_2 = SerializedWorkspace {
|
||||
id: WorkspaceId(2),
|
||||
location: SerializedWorkspaceLocation::from_local_paths(["/tmp2"]),
|
||||
center_group: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: Some("session-id-1".to_owned()),
|
||||
};
|
||||
|
||||
let workspace_3 = SerializedWorkspace {
|
||||
id: WorkspaceId(3),
|
||||
location: SerializedWorkspaceLocation::from_local_paths(["/tmp3"]),
|
||||
center_group: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: Some("session-id-2".to_owned()),
|
||||
};
|
||||
|
||||
let workspace_4 = SerializedWorkspace {
|
||||
id: WorkspaceId(4),
|
||||
location: SerializedWorkspaceLocation::from_local_paths(["/tmp4"]),
|
||||
center_group: Default::default(),
|
||||
window_bounds: Default::default(),
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: None,
|
||||
};
|
||||
|
||||
db.save_workspace(workspace_1.clone()).await;
|
||||
db.save_workspace(workspace_2.clone()).await;
|
||||
db.save_workspace(workspace_3.clone()).await;
|
||||
db.save_workspace(workspace_4.clone()).await;
|
||||
|
||||
let locations = db
|
||||
.session_workspace_locations("session-id-1".to_owned())
|
||||
.unwrap();
|
||||
assert_eq!(locations.len(), 2);
|
||||
assert_eq!(locations[0], LocalPaths::new(["/tmp1"]));
|
||||
assert_eq!(locations[1], LocalPaths::new(["/tmp2"]));
|
||||
|
||||
let locations = db
|
||||
.session_workspace_locations("session-id-2".to_owned())
|
||||
.unwrap();
|
||||
assert_eq!(locations.len(), 1);
|
||||
assert_eq!(locations[0], LocalPaths::new(["/tmp3"]));
|
||||
}
|
||||
|
||||
use crate::persistence::model::SerializedWorkspace;
|
||||
use crate::persistence::model::{SerializedItem, SerializedPane, SerializedPaneGroup};
|
||||
|
||||
@@ -1294,6 +1404,7 @@ mod tests {
|
||||
display: Default::default(),
|
||||
docks: Default::default(),
|
||||
centered_layout: false,
|
||||
session_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user