Restructure persistence of remote workspaces to make room for WSL and other non-ssh remote projects (#36714)

This is another pure refactor, to prepare for adding direct WSL support.

###  Todo

* [x] Represent `paths` in the same way for all workspaces, instead of
having a completely separate SSH representation
* [x] Adjust sqlite tables
    * [x] `ssh_projects` -> `ssh_connections` (drop paths)
    * [x] `workspaces.local_paths` -> `paths`
    * [x] remove duplicate path columns on `workspaces`
* [x] Add migrations for backward-compatibility

Release Notes:

- N/A

---------

Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
This commit is contained in:
Max Brunsfeld 2025-08-22 14:10:45 -07:00 committed by GitHub
parent 639417c2bc
commit f649c31bf9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 784 additions and 1080 deletions

View file

@ -47,8 +47,8 @@ use theme::{
use util::{ResultExt, TryFutureExt, maybe};
use uuid::Uuid;
use workspace::{
AppState, SerializedWorkspaceLocation, Toast, Workspace, WorkspaceSettings, WorkspaceStore,
notifications::NotificationId,
AppState, PathList, SerializedWorkspaceLocation, Toast, Workspace, WorkspaceSettings,
WorkspaceStore, notifications::NotificationId,
};
use zed::{
OpenListener, OpenRequest, RawOpenRequest, app_menus, build_window_options,
@ -949,15 +949,14 @@ async fn restore_or_create_workspace(app_state: Arc<AppState>, cx: &mut AsyncApp
if let Some(locations) = restorable_workspace_locations(cx, &app_state).await {
let mut tasks = Vec::new();
for location in locations {
for (location, paths) in locations {
match location {
SerializedWorkspaceLocation::Local(location, _) => {
SerializedWorkspaceLocation::Local => {
let app_state = app_state.clone();
let paths = location.paths().to_vec();
let task = cx.spawn(async move |cx| {
let open_task = cx.update(|cx| {
workspace::open_paths(
&paths,
&paths.paths(),
app_state,
workspace::OpenOptions::default(),
cx,
@ -979,7 +978,7 @@ async fn restore_or_create_workspace(app_state: Arc<AppState>, cx: &mut AsyncApp
match connection_options {
Ok(connection_options) => recent_projects::open_ssh_project(
connection_options,
ssh.paths.into_iter().map(PathBuf::from).collect(),
paths.paths().into_iter().map(PathBuf::from).collect(),
app_state,
workspace::OpenOptions::default(),
cx,
@ -1070,7 +1069,7 @@ async fn restore_or_create_workspace(app_state: Arc<AppState>, cx: &mut AsyncApp
pub(crate) async fn restorable_workspace_locations(
cx: &mut AsyncApp,
app_state: &Arc<AppState>,
) -> Option<Vec<SerializedWorkspaceLocation>> {
) -> Option<Vec<(SerializedWorkspaceLocation, PathList)>> {
let mut restore_behavior = cx
.update(|cx| WorkspaceSettings::get(None, cx).restore_on_startup)
.ok()?;

View file

@ -26,6 +26,7 @@ use std::thread;
use std::time::Duration;
use util::ResultExt;
use util::paths::PathWithPosition;
use workspace::PathList;
use workspace::item::ItemHandle;
use workspace::{AppState, OpenOptions, SerializedWorkspaceLocation, Workspace};
@ -361,12 +362,14 @@ async fn open_workspaces(
if open_new_workspace == Some(true) {
Vec::new()
} else {
let locations = restorable_workspace_locations(cx, &app_state).await;
locations.unwrap_or_default()
restorable_workspace_locations(cx, &app_state)
.await
.unwrap_or_default()
}
} else {
vec![SerializedWorkspaceLocation::from_local_paths(
paths.into_iter().map(PathBuf::from),
vec![(
SerializedWorkspaceLocation::Local,
PathList::new(&paths.into_iter().map(PathBuf::from).collect::<Vec<_>>()),
)]
};
@ -394,9 +397,9 @@ async fn open_workspaces(
// If there are paths to open, open a workspace for each grouping of paths
let mut errored = false;
for location in grouped_locations {
for (location, workspace_paths) in grouped_locations {
match location {
SerializedWorkspaceLocation::Local(workspace_paths, _) => {
SerializedWorkspaceLocation::Local => {
let workspace_paths = workspace_paths
.paths()
.iter()
@ -429,7 +432,7 @@ async fn open_workspaces(
cx.spawn(async move |cx| {
open_ssh_project(
connection_options,
ssh.paths.into_iter().map(PathBuf::from).collect(),
workspace_paths.paths().to_vec(),
app_state,
OpenOptions::default(),
cx,