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:
parent
639417c2bc
commit
f649c31bf9
12 changed files with 784 additions and 1080 deletions
|
@ -1,5 +1,3 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use gpui::{ClickEvent, DismissEvent, EventEmitter, FocusHandle, Focusable, Render, WeakEntity};
|
||||
use project::project_settings::ProjectSettings;
|
||||
use remote::SshConnectionOptions;
|
||||
|
@ -103,17 +101,17 @@ impl DisconnectedOverlay {
|
|||
return;
|
||||
};
|
||||
|
||||
let Some(ssh_project) = workspace.read(cx).serialized_ssh_project() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(window_handle) = window.window_handle().downcast::<Workspace>() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let app_state = workspace.read(cx).app_state().clone();
|
||||
|
||||
let paths = ssh_project.paths.iter().map(PathBuf::from).collect();
|
||||
let paths = workspace
|
||||
.read(cx)
|
||||
.root_paths(cx)
|
||||
.iter()
|
||||
.map(|path| path.to_path_buf())
|
||||
.collect();
|
||||
|
||||
cx.spawn_in(window, async move |_, cx| {
|
||||
open_ssh_project(
|
||||
|
|
|
@ -19,15 +19,12 @@ use picker::{
|
|||
pub use remote_servers::RemoteServerProjects;
|
||||
use settings::Settings;
|
||||
pub use ssh_connections::SshSettings;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{path::Path, sync::Arc};
|
||||
use ui::{KeyBinding, ListItem, ListItemSpacing, Tooltip, prelude::*, tooltip_container};
|
||||
use util::{ResultExt, paths::PathExt};
|
||||
use workspace::{
|
||||
CloseIntent, HistoryManager, ModalView, OpenOptions, SerializedWorkspaceLocation, WORKSPACE_DB,
|
||||
Workspace, WorkspaceId, with_active_or_new_workspace,
|
||||
CloseIntent, HistoryManager, ModalView, OpenOptions, PathList, SerializedWorkspaceLocation,
|
||||
WORKSPACE_DB, Workspace, WorkspaceId, with_active_or_new_workspace,
|
||||
};
|
||||
use zed_actions::{OpenRecent, OpenRemote};
|
||||
|
||||
|
@ -154,7 +151,7 @@ impl Render for RecentProjects {
|
|||
|
||||
pub struct RecentProjectsDelegate {
|
||||
workspace: WeakEntity<Workspace>,
|
||||
workspaces: Vec<(WorkspaceId, SerializedWorkspaceLocation)>,
|
||||
workspaces: Vec<(WorkspaceId, SerializedWorkspaceLocation, PathList)>,
|
||||
selected_match_index: usize,
|
||||
matches: Vec<StringMatch>,
|
||||
render_paths: bool,
|
||||
|
@ -178,12 +175,15 @@ impl RecentProjectsDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_workspaces(&mut self, workspaces: Vec<(WorkspaceId, SerializedWorkspaceLocation)>) {
|
||||
pub fn set_workspaces(
|
||||
&mut self,
|
||||
workspaces: Vec<(WorkspaceId, SerializedWorkspaceLocation, PathList)>,
|
||||
) {
|
||||
self.workspaces = workspaces;
|
||||
self.has_any_non_local_projects = !self
|
||||
.workspaces
|
||||
.iter()
|
||||
.all(|(_, location)| matches!(location, SerializedWorkspaceLocation::Local(_, _)));
|
||||
.all(|(_, location, _)| matches!(location, SerializedWorkspaceLocation::Local));
|
||||
}
|
||||
}
|
||||
impl EventEmitter<DismissEvent> for RecentProjectsDelegate {}
|
||||
|
@ -236,15 +236,14 @@ impl PickerDelegate for RecentProjectsDelegate {
|
|||
.workspaces
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, (id, _))| !self.is_current_workspace(*id, cx))
|
||||
.map(|(id, (_, location))| {
|
||||
let combined_string = location
|
||||
.sorted_paths()
|
||||
.filter(|(_, (id, _, _))| !self.is_current_workspace(*id, cx))
|
||||
.map(|(id, (_, _, paths))| {
|
||||
let combined_string = paths
|
||||
.paths()
|
||||
.iter()
|
||||
.map(|path| path.compact().to_string_lossy().into_owned())
|
||||
.collect::<Vec<_>>()
|
||||
.join("");
|
||||
|
||||
StringMatchCandidate::new(id, &combined_string)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -279,7 +278,7 @@ impl PickerDelegate for RecentProjectsDelegate {
|
|||
.get(self.selected_index())
|
||||
.zip(self.workspace.upgrade())
|
||||
{
|
||||
let (candidate_workspace_id, candidate_workspace_location) =
|
||||
let (candidate_workspace_id, candidate_workspace_location, candidate_workspace_paths) =
|
||||
&self.workspaces[selected_match.candidate_id];
|
||||
let replace_current_window = if self.create_new_window {
|
||||
secondary
|
||||
|
@ -292,8 +291,8 @@ impl PickerDelegate for RecentProjectsDelegate {
|
|||
Task::ready(Ok(()))
|
||||
} else {
|
||||
match candidate_workspace_location {
|
||||
SerializedWorkspaceLocation::Local(paths, _) => {
|
||||
let paths = paths.paths().to_vec();
|
||||
SerializedWorkspaceLocation::Local => {
|
||||
let paths = candidate_workspace_paths.paths().to_vec();
|
||||
if replace_current_window {
|
||||
cx.spawn_in(window, async move |workspace, cx| {
|
||||
let continue_replacing = workspace
|
||||
|
@ -321,7 +320,7 @@ impl PickerDelegate for RecentProjectsDelegate {
|
|||
workspace.open_workspace_for_paths(false, paths, window, cx)
|
||||
}
|
||||
}
|
||||
SerializedWorkspaceLocation::Ssh(ssh_project) => {
|
||||
SerializedWorkspaceLocation::Ssh(connection) => {
|
||||
let app_state = workspace.app_state().clone();
|
||||
|
||||
let replace_window = if replace_current_window {
|
||||
|
@ -337,12 +336,12 @@ impl PickerDelegate for RecentProjectsDelegate {
|
|||
|
||||
let connection_options = SshSettings::get_global(cx)
|
||||
.connection_options_for(
|
||||
ssh_project.host.clone(),
|
||||
ssh_project.port,
|
||||
ssh_project.user.clone(),
|
||||
connection.host.clone(),
|
||||
connection.port,
|
||||
connection.user.clone(),
|
||||
);
|
||||
|
||||
let paths = ssh_project.paths.iter().map(PathBuf::from).collect();
|
||||
let paths = candidate_workspace_paths.paths().to_vec();
|
||||
|
||||
cx.spawn_in(window, async move |_, cx| {
|
||||
open_ssh_project(
|
||||
|
@ -383,12 +382,12 @@ impl PickerDelegate for RecentProjectsDelegate {
|
|||
) -> Option<Self::ListItem> {
|
||||
let hit = self.matches.get(ix)?;
|
||||
|
||||
let (_, location) = self.workspaces.get(hit.candidate_id)?;
|
||||
let (_, location, paths) = self.workspaces.get(hit.candidate_id)?;
|
||||
|
||||
let mut path_start_offset = 0;
|
||||
|
||||
let (match_labels, paths): (Vec<_>, Vec<_>) = location
|
||||
.sorted_paths()
|
||||
let (match_labels, paths): (Vec<_>, Vec<_>) = paths
|
||||
.paths()
|
||||
.iter()
|
||||
.map(|p| p.compact())
|
||||
.map(|path| {
|
||||
|
@ -416,11 +415,9 @@ impl PickerDelegate for RecentProjectsDelegate {
|
|||
.gap_3()
|
||||
.when(self.has_any_non_local_projects, |this| {
|
||||
this.child(match location {
|
||||
SerializedWorkspaceLocation::Local(_, _) => {
|
||||
Icon::new(IconName::Screen)
|
||||
.color(Color::Muted)
|
||||
.into_any_element()
|
||||
}
|
||||
SerializedWorkspaceLocation::Local => Icon::new(IconName::Screen)
|
||||
.color(Color::Muted)
|
||||
.into_any_element(),
|
||||
SerializedWorkspaceLocation::Ssh(_) => Icon::new(IconName::Server)
|
||||
.color(Color::Muted)
|
||||
.into_any_element(),
|
||||
|
@ -568,7 +565,7 @@ impl RecentProjectsDelegate {
|
|||
cx: &mut Context<Picker<Self>>,
|
||||
) {
|
||||
if let Some(selected_match) = self.matches.get(ix) {
|
||||
let (workspace_id, _) = self.workspaces[selected_match.candidate_id];
|
||||
let (workspace_id, _, _) = self.workspaces[selected_match.candidate_id];
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let _ = WORKSPACE_DB.delete_workspace_by_id(workspace_id).await;
|
||||
let workspaces = WORKSPACE_DB
|
||||
|
@ -707,7 +704,8 @@ mod tests {
|
|||
}];
|
||||
delegate.set_workspaces(vec![(
|
||||
WorkspaceId::default(),
|
||||
SerializedWorkspaceLocation::from_local_paths(vec![path!("/test/path/")]),
|
||||
SerializedWorkspaceLocation::Local,
|
||||
PathList::new(&[path!("/test/path")]),
|
||||
)]);
|
||||
});
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue