ssh remote: Handle disconnect on project and show overlay (#19014)
Demo: https://github.com/user-attachments/assets/e5edf8f3-8c15-482e-a792-6eb619f83de4 Release Notes: - N/A --------- Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
parent
e3ff2ced79
commit
b75532fad7
16 changed files with 264 additions and 78 deletions
|
@ -647,17 +647,10 @@ pub struct FormattableBuffer {
|
|||
}
|
||||
|
||||
pub struct RemoteLspStore {
|
||||
upstream_client: AnyProtoClient,
|
||||
upstream_client: Option<AnyProtoClient>,
|
||||
upstream_project_id: u64,
|
||||
}
|
||||
|
||||
impl RemoteLspStore {}
|
||||
|
||||
// pub struct SshLspStore {
|
||||
// upstream_client: AnyProtoClient,
|
||||
// current_lsp_settings: HashMap<LanguageServerName, LspSettings>,
|
||||
// }
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum LspStoreMode {
|
||||
Local(LocalLspStore), // ssh host and collab host
|
||||
|
@ -808,10 +801,15 @@ impl LspStore {
|
|||
pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
|
||||
match &self.mode {
|
||||
LspStoreMode::Remote(RemoteLspStore {
|
||||
upstream_client,
|
||||
upstream_client: Some(upstream_client),
|
||||
upstream_project_id,
|
||||
..
|
||||
}) => Some((upstream_client.clone(), *upstream_project_id)),
|
||||
|
||||
LspStoreMode::Remote(RemoteLspStore {
|
||||
upstream_client: None,
|
||||
..
|
||||
}) => None,
|
||||
LspStoreMode::Local(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -924,7 +922,7 @@ impl LspStore {
|
|||
|
||||
Self {
|
||||
mode: LspStoreMode::Remote(RemoteLspStore {
|
||||
upstream_client,
|
||||
upstream_client: Some(upstream_client),
|
||||
upstream_project_id: project_id,
|
||||
}),
|
||||
downstream_client: None,
|
||||
|
@ -3099,6 +3097,15 @@ impl LspStore {
|
|||
self.downstream_client.take();
|
||||
}
|
||||
|
||||
pub fn disconnected_from_ssh_remote(&mut self) {
|
||||
if let LspStoreMode::Remote(RemoteLspStore {
|
||||
upstream_client, ..
|
||||
}) = &mut self.mode
|
||||
{
|
||||
upstream_client.take();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_language_server_statuses_from_proto(
|
||||
&mut self,
|
||||
language_servers: Vec<proto::LanguageServer>,
|
||||
|
|
|
@ -58,7 +58,7 @@ use node_runtime::NodeRuntime;
|
|||
use parking_lot::{Mutex, RwLock};
|
||||
pub use prettier_store::PrettierStore;
|
||||
use project_settings::{ProjectSettings, SettingsObserver, SettingsObserverEvent};
|
||||
use remote::SshRemoteClient;
|
||||
use remote::{SshConnectionOptions, SshRemoteClient};
|
||||
use rpc::{proto::SSH_PROJECT_ID, AnyProtoClient, ErrorCode};
|
||||
use search::{SearchInputKind, SearchQuery, SearchResult};
|
||||
use search_history::SearchHistory;
|
||||
|
@ -245,6 +245,7 @@ pub enum Event {
|
|||
},
|
||||
RemoteIdChanged(Option<u64>),
|
||||
DisconnectedFromHost,
|
||||
DisconnectedFromSshRemote,
|
||||
Closed,
|
||||
DeletedEntry(ProjectEntryId),
|
||||
CollaboratorUpdated {
|
||||
|
@ -755,6 +756,8 @@ impl Project {
|
|||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
cx.subscribe(&ssh, Self::on_ssh_event).detach();
|
||||
cx.observe(&ssh, |_, _, cx| cx.notify()).detach();
|
||||
|
||||
let this = Self {
|
||||
|
@ -1313,6 +1316,12 @@ impl Project {
|
|||
.map(|ssh| ssh.read(cx).connection_state())
|
||||
}
|
||||
|
||||
pub fn ssh_connection_options(&self, cx: &AppContext) -> Option<SshConnectionOptions> {
|
||||
self.ssh_client
|
||||
.as_ref()
|
||||
.map(|ssh| ssh.read(cx).connection_options())
|
||||
}
|
||||
|
||||
pub fn replica_id(&self) -> ReplicaId {
|
||||
match self.client_state {
|
||||
ProjectClientState::Remote { replica_id, .. } => replica_id,
|
||||
|
@ -1658,7 +1667,7 @@ impl Project {
|
|||
}
|
||||
|
||||
pub fn disconnected_from_host(&mut self, cx: &mut ModelContext<Self>) {
|
||||
if self.is_disconnected() {
|
||||
if self.is_disconnected(cx) {
|
||||
return;
|
||||
}
|
||||
self.disconnected_from_host_internal(cx);
|
||||
|
@ -1708,16 +1717,24 @@ impl Project {
|
|||
cx.emit(Event::Closed);
|
||||
}
|
||||
|
||||
pub fn is_disconnected(&self) -> bool {
|
||||
pub fn is_disconnected(&self, cx: &AppContext) -> bool {
|
||||
match &self.client_state {
|
||||
ProjectClientState::Remote {
|
||||
sharing_has_stopped,
|
||||
..
|
||||
} => *sharing_has_stopped,
|
||||
ProjectClientState::Local if self.is_via_ssh() => self.ssh_is_disconnected(cx),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn ssh_is_disconnected(&self, cx: &AppContext) -> bool {
|
||||
self.ssh_client
|
||||
.as_ref()
|
||||
.map(|ssh| ssh.read(cx).is_disconnected())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn capability(&self) -> Capability {
|
||||
match &self.client_state {
|
||||
ProjectClientState::Remote { capability, .. } => *capability,
|
||||
|
@ -1725,8 +1742,8 @@ impl Project {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_read_only(&self) -> bool {
|
||||
self.is_disconnected() || self.capability() == Capability::ReadOnly
|
||||
pub fn is_read_only(&self, cx: &AppContext) -> bool {
|
||||
self.is_disconnected(cx) || self.capability() == Capability::ReadOnly
|
||||
}
|
||||
|
||||
pub fn is_local(&self) -> bool {
|
||||
|
@ -1807,7 +1824,7 @@ impl Project {
|
|||
path: impl Into<ProjectPath>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Model<Buffer>>> {
|
||||
if self.is_via_collab() && self.is_disconnected() {
|
||||
if (self.is_via_collab() || self.is_via_ssh()) && self.is_disconnected(cx) {
|
||||
return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
|
||||
}
|
||||
|
||||
|
@ -2114,6 +2131,30 @@ impl Project {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_ssh_event(
|
||||
&mut self,
|
||||
_: Model<SshRemoteClient>,
|
||||
event: &remote::SshRemoteEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
match event {
|
||||
remote::SshRemoteEvent::Disconnected => {
|
||||
// if self.is_via_ssh() {
|
||||
// self.collaborators.clear();
|
||||
self.worktree_store.update(cx, |store, cx| {
|
||||
store.disconnected_from_host(cx);
|
||||
});
|
||||
self.buffer_store.update(cx, |buffer_store, cx| {
|
||||
buffer_store.disconnected_from_host(cx)
|
||||
});
|
||||
self.lsp_store.update(cx, |lsp_store, _cx| {
|
||||
lsp_store.disconnected_from_ssh_remote()
|
||||
});
|
||||
cx.emit(Event::DisconnectedFromSshRemote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_settings_observer_event(
|
||||
&mut self,
|
||||
_: Model<SettingsObserver>,
|
||||
|
|
|
@ -509,6 +509,11 @@ impl WorktreeStore {
|
|||
for worktree in &self.worktrees {
|
||||
if let Some(worktree) = worktree.upgrade() {
|
||||
worktree.update(cx, |worktree, _| {
|
||||
println!(
|
||||
"worktree. is_local: {:?}, is_remote: {:?}",
|
||||
worktree.is_local(),
|
||||
worktree.is_remote()
|
||||
);
|
||||
if let Some(worktree) = worktree.as_remote_mut() {
|
||||
worktree.disconnected_from_host();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue