Workspace persistence for SSH projects (#17996)
TODOs: - [x] Add tests to `workspace/src/persistence.rs` - [x] Add a icon for ssh projects - [x] Fix all `TODO` comments - [x] Use `port` if it's passed in the ssh connection options In next PRs: - Make sure unsaved buffers are persisted/restored, along with other items/layout - Handle multiple paths/worktrees correctly Release Notes: - N/A --------- Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
This commit is contained in:
parent
7d0a7541bf
commit
e9f2e72ff0
12 changed files with 592 additions and 141 deletions
|
@ -11,6 +11,7 @@ use db::sqlez::{
|
|||
};
|
||||
use gpui::{AsyncWindowContext, Model, View, WeakView};
|
||||
use project::Project;
|
||||
use remote::ssh_session::SshProjectId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
|
@ -20,6 +21,69 @@ use ui::SharedString;
|
|||
use util::ResultExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
pub struct SerializedSshProject {
|
||||
pub id: SshProjectId,
|
||||
pub host: String,
|
||||
pub port: Option<u16>,
|
||||
pub path: String,
|
||||
pub user: Option<String>,
|
||||
}
|
||||
|
||||
impl SerializedSshProject {
|
||||
pub fn ssh_url(&self) -> String {
|
||||
let mut result = String::from("ssh://");
|
||||
if let Some(user) = &self.user {
|
||||
result.push_str(user);
|
||||
result.push('@');
|
||||
}
|
||||
result.push_str(&self.host);
|
||||
if let Some(port) = &self.port {
|
||||
result.push(':');
|
||||
result.push_str(&port.to_string());
|
||||
}
|
||||
result.push_str(&self.path);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticColumnCount for SerializedSshProject {
|
||||
fn column_count() -> usize {
|
||||
5
|
||||
}
|
||||
}
|
||||
|
||||
impl Bind for &SerializedSshProject {
|
||||
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
|
||||
let next_index = statement.bind(&self.id.0, start_index)?;
|
||||
let next_index = statement.bind(&self.host, next_index)?;
|
||||
let next_index = statement.bind(&self.port, next_index)?;
|
||||
let next_index = statement.bind(&self.path, next_index)?;
|
||||
statement.bind(&self.user, next_index)
|
||||
}
|
||||
}
|
||||
|
||||
impl Column for SerializedSshProject {
|
||||
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
|
||||
let id = statement.column_int64(start_index)?;
|
||||
let host = statement.column_text(start_index + 1)?.to_string();
|
||||
let (port, _) = Option::<u16>::column(statement, start_index + 2)?;
|
||||
let path = statement.column_text(start_index + 3)?.to_string();
|
||||
let (user, _) = Option::<String>::column(statement, start_index + 4)?;
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
id: SshProjectId(id as u64),
|
||||
host,
|
||||
port,
|
||||
path,
|
||||
user,
|
||||
},
|
||||
start_index + 5,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
pub struct SerializedDevServerProject {
|
||||
pub id: DevServerProjectId,
|
||||
|
@ -58,7 +122,6 @@ impl Column for LocalPaths {
|
|||
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
|
||||
let path_blob = statement.column_blob(start_index)?;
|
||||
let paths: Arc<Vec<PathBuf>> = if path_blob.is_empty() {
|
||||
println!("path blog is empty");
|
||||
Default::default()
|
||||
} else {
|
||||
bincode::deserialize(path_blob).context("Bincode deserialization of paths failed")?
|
||||
|
@ -146,6 +209,7 @@ impl Column for SerializedDevServerProject {
|
|||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum SerializedWorkspaceLocation {
|
||||
Local(LocalPaths, LocalPathsOrder),
|
||||
Ssh(SerializedSshProject),
|
||||
DevServer(SerializedDevServerProject),
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue