remote: Fix naming inconsistencies (#46146)

Lukas Wirth created

Renames a bunch of ssh things to remote when its actually about remotes
in general

Release Notes:

- N/A *or* Added/Fixed/Improved ...

Change summary

crates/project/src/project.rs                      |   4 
crates/recent_projects/src/disconnected_overlay.rs |  11 
crates/recent_projects/src/recent_projects.rs      |   4 
crates/recent_projects/src/remote_connections.rs   |   8 
crates/recent_projects/src/remote_servers.rs       |  17 +-
crates/remote/src/remote_client.rs                 | 107 ++++++++-------
crates/remote/src/transport/docker.rs              |  32 ----
crates/remote_server/Cargo.toml                    |   2 
crates/remote_server/src/headless_project.rs       |   6 
crates/remote_server/src/main.rs                   |  18 +-
crates/remote_server/src/unix.rs                   |   6 
crates/workspace/src/workspace.rs                  |   2 
crates/zed/src/main.rs                             |   4 
crates/zed/src/zed/open_listener.rs                |   6 
14 files changed, 110 insertions(+), 117 deletions(-)

Detailed changes

crates/project/src/project.rs 🔗

@@ -331,7 +331,7 @@ pub enum Event {
     },
     RemoteIdChanged(Option<u64>),
     DisconnectedFromHost,
-    DisconnectedFromSshRemote,
+    DisconnectedFromRemote,
     Closed,
     DeletedEntry(WorktreeId, ProjectEntryId),
     CollaboratorUpdated {
@@ -3296,7 +3296,7 @@ impl Project {
                 self.lsp_store.update(cx, |lsp_store, _cx| {
                     lsp_store.disconnected_from_ssh_remote()
                 });
-                cx.emit(Event::DisconnectedFromSshRemote);
+                cx.emit(Event::DisconnectedFromRemote);
             }
         }
     }

crates/recent_projects/src/disconnected_overlay.rs 🔗

@@ -57,16 +57,15 @@ impl DisconnectedOverlay {
             |workspace, project, event, window, cx| {
                 if !matches!(
                     event,
-                    project::Event::DisconnectedFromHost
-                        | project::Event::DisconnectedFromSshRemote
+                    project::Event::DisconnectedFromHost | project::Event::DisconnectedFromRemote
                 ) {
                     return;
                 }
                 let handle = cx.entity().downgrade();
 
                 let remote_connection_options = project.read(cx).remote_connection_options(cx);
-                let host = if let Some(ssh_connection_options) = remote_connection_options {
-                    Host::RemoteServerProject(ssh_connection_options)
+                let host = if let Some(remote_connection_options) = remote_connection_options {
+                    Host::RemoteServerProject(remote_connection_options)
                 } else {
                     Host::CollabGuestProject
                 };
@@ -86,8 +85,8 @@ impl DisconnectedOverlay {
         self.finished = true;
         cx.emit(DismissEvent);
 
-        if let Host::RemoteServerProject(ssh_connection_options) = &self.host {
-            self.reconnect_to_remote_project(ssh_connection_options.clone(), window, cx);
+        if let Host::RemoteServerProject(remote_connection_options) = &self.host {
+            self.reconnect_to_remote_project(remote_connection_options.clone(), window, cx);
         }
     }
 

crates/recent_projects/src/recent_projects.rs 🔗

@@ -24,7 +24,7 @@ use picker::{
     Picker, PickerDelegate,
     highlighted_match_with_paths::{HighlightedMatch, HighlightedMatchWithPaths},
 };
-pub use remote_connections::SshSettings;
+pub use remote_connections::RemoteSettings;
 pub use remote_servers::RemoteServerProjects;
 use settings::Settings;
 use std::{path::Path, sync::Arc};
@@ -585,7 +585,7 @@ impl PickerDelegate for RecentProjectsDelegate {
                         };
 
                         if let RemoteConnectionOptions::Ssh(connection) = &mut connection {
-                            SshSettings::get_global(cx)
+                            RemoteSettings::get_global(cx)
                                 .fill_connection_options_from_settings(connection);
                         };
 

crates/recent_projects/src/remote_connections.rs 🔗

@@ -34,14 +34,14 @@ use util::paths::PathWithPosition;
 use workspace::{AppState, ModalView, Workspace};
 
 #[derive(RegisterSetting)]
-pub struct SshSettings {
+pub struct RemoteSettings {
     pub ssh_connections: ExtendingVec<SshConnection>,
     pub wsl_connections: ExtendingVec<WslConnection>,
     /// Whether to read ~/.ssh/config for ssh connection sources.
     pub read_ssh_config: bool,
 }
 
-impl SshSettings {
+impl RemoteSettings {
     pub fn ssh_connections(&self) -> impl Iterator<Item = SshConnection> + use<> {
         self.ssh_connections.clone().0.into_iter()
     }
@@ -117,7 +117,7 @@ impl From<WslConnection> for Connection {
     }
 }
 
-impl Settings for SshSettings {
+impl Settings for RemoteSettings {
     fn from_settings(content: &settings::SettingsContent) -> Self {
         let remote = &content.remote;
         Self {
@@ -633,7 +633,7 @@ pub async fn open_remote_project(
                 workspace::remote_workspace_position_from_db(connection_options.clone(), &paths, cx)
             })?
             .await
-            .context("fetching ssh workspace position from db")?;
+            .context("fetching remote workspace position from db")?;
 
         let mut options =
             cx.update(|cx| (app_state.build_window_options)(workspace_position.display, cx))?;

crates/recent_projects/src/remote_servers.rs 🔗

@@ -1,9 +1,8 @@
 use crate::{
     dev_container::start_dev_container,
     remote_connections::{
-        Connection, RemoteConnectionModal, RemoteConnectionPrompt, SshConnection,
-        SshConnectionHeader, SshSettings, connect, determine_paths_with_positions,
-        open_remote_project,
+        Connection, RemoteConnectionModal, RemoteConnectionPrompt, RemoteSettings, SshConnection,
+        SshConnectionHeader, connect, determine_paths_with_positions, open_remote_project,
     },
     ssh_config::parse_ssh_config_hosts,
 };
@@ -188,7 +187,7 @@ impl EditNicknameState {
             index,
             editor: cx.new(|cx| Editor::single_line(window, cx)),
         };
-        let starting_text = SshSettings::get_global(cx)
+        let starting_text = RemoteSettings::get_global(cx)
             .ssh_connections()
             .nth(index.0)
             .and_then(|state| state.nickname)
@@ -493,7 +492,7 @@ impl DefaultState {
         let add_new_devcontainer = NavigableEntry::new(&handle, cx);
         let add_new_wsl = NavigableEntry::new(&handle, cx);
 
-        let ssh_settings = SshSettings::get_global(cx);
+        let ssh_settings = RemoteSettings::get_global(cx);
         let read_ssh_config = ssh_settings.read_ssh_config;
 
         let ssh_servers = ssh_settings
@@ -687,7 +686,7 @@ impl RemoteServerProjects {
         cx: &mut Context<Self>,
     ) -> Self {
         let focus_handle = cx.focus_handle();
-        let mut read_ssh_config = SshSettings::get_global(cx).read_ssh_config;
+        let mut read_ssh_config = RemoteSettings::get_global(cx).read_ssh_config;
         let ssh_config_updates = if read_ssh_config {
             spawn_ssh_config_watch(fs.clone(), cx)
         } else {
@@ -702,7 +701,7 @@ impl RemoteServerProjects {
 
         let _subscription =
             cx.observe_global_in::<SettingsStore>(window, move |recent_projects, _, cx| {
-                let new_read_ssh_config = SshSettings::get_global(cx).read_ssh_config;
+                let new_read_ssh_config = RemoteSettings::get_global(cx).read_ssh_config;
                 if read_ssh_config != new_read_ssh_config {
                     read_ssh_config = new_read_ssh_config;
                     if read_ssh_config {
@@ -2328,7 +2327,7 @@ impl RemoteServerProjects {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> impl IntoElement {
-        let Some(connection) = SshSettings::get_global(cx)
+        let Some(connection) = RemoteSettings::get_global(cx)
             .ssh_connections()
             .nth(state.index.0)
         else {
@@ -2368,7 +2367,7 @@ impl RemoteServerProjects {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> impl IntoElement {
-        let ssh_settings = SshSettings::get_global(cx);
+        let ssh_settings = RemoteSettings::get_global(cx);
         let mut should_rebuild = false;
 
         let ssh_connections_changed = ssh_settings.ssh_connections.0.iter().ne(state

crates/remote/src/remote_client.rs 🔗

@@ -154,7 +154,7 @@ enum State {
     HeartbeatMissed {
         missed_heartbeats: usize,
 
-        ssh_connection: Arc<dyn RemoteConnection>,
+        remote_connection: Arc<dyn RemoteConnection>,
         delegate: Arc<dyn RemoteClientDelegate>,
 
         multiplex_task: Task<Result<()>>,
@@ -162,7 +162,7 @@ enum State {
     },
     Reconnecting,
     ReconnectFailed {
-        ssh_connection: Arc<dyn RemoteConnection>,
+        remote_connection: Arc<dyn RemoteConnection>,
         delegate: Arc<dyn RemoteClientDelegate>,
 
         error: anyhow::Error,
@@ -190,11 +190,14 @@ impl State {
     fn remote_connection(&self) -> Option<Arc<dyn RemoteConnection>> {
         match self {
             Self::Connected {
-                remote_connection: ssh_connection,
-                ..
-            } => Some(ssh_connection.clone()),
-            Self::HeartbeatMissed { ssh_connection, .. } => Some(ssh_connection.clone()),
-            Self::ReconnectFailed { ssh_connection, .. } => Some(ssh_connection.clone()),
+                remote_connection, ..
+            } => Some(remote_connection.clone()),
+            Self::HeartbeatMissed {
+                remote_connection, ..
+            } => Some(remote_connection.clone()),
+            Self::ReconnectFailed {
+                remote_connection, ..
+            } => Some(remote_connection.clone()),
             _ => None,
         }
     }
@@ -230,13 +233,13 @@ impl State {
     fn heartbeat_recovered(self) -> Self {
         match self {
             Self::HeartbeatMissed {
-                ssh_connection,
+                remote_connection,
                 delegate,
                 multiplex_task,
                 heartbeat_task,
                 ..
             } => Self::Connected {
-                remote_connection: ssh_connection,
+                remote_connection: remote_connection,
                 delegate,
                 multiplex_task,
                 heartbeat_task,
@@ -248,26 +251,26 @@ impl State {
     fn heartbeat_missed(self) -> Self {
         match self {
             Self::Connected {
-                remote_connection: ssh_connection,
+                remote_connection,
                 delegate,
                 multiplex_task,
                 heartbeat_task,
             } => Self::HeartbeatMissed {
                 missed_heartbeats: 1,
-                ssh_connection,
+                remote_connection,
                 delegate,
                 multiplex_task,
                 heartbeat_task,
             },
             Self::HeartbeatMissed {
                 missed_heartbeats,
-                ssh_connection,
+                remote_connection,
                 delegate,
                 multiplex_task,
                 heartbeat_task,
             } => Self::HeartbeatMissed {
                 missed_heartbeats: missed_heartbeats + 1,
-                ssh_connection,
+                remote_connection,
                 delegate,
                 multiplex_task,
                 heartbeat_task,
@@ -493,7 +496,7 @@ impl RemoteClient {
         let State::Connected {
             multiplex_task,
             heartbeat_task,
-            remote_connection: ssh_connection,
+            remote_connection,
             delegate,
         } = state
         else {
@@ -511,12 +514,12 @@ impl RemoteClient {
                 executor.timer(Duration::from_millis(50)).await;
             }
 
-            // Drop `multiplex_task` because it owns our ssh_proxy_process, which is a
+            // Drop `multiplex_task` because it owns our remote_connection_proxy_process, which is a
             // child of master_process.
             drop(multiplex_task);
             // Now drop the rest of state, which kills master process.
             drop(heartbeat_task);
-            drop(ssh_connection);
+            drop(remote_connection);
             drop(delegate);
         })
     }
@@ -540,13 +543,13 @@ impl RemoteClient {
         let state = self.state.take().unwrap();
         let (attempts, remote_connection, delegate) = match state {
             State::Connected {
-                remote_connection: ssh_connection,
+                remote_connection,
                 delegate,
                 multiplex_task,
                 heartbeat_task,
             }
             | State::HeartbeatMissed {
-                ssh_connection,
+                remote_connection,
                 delegate,
                 multiplex_task,
                 heartbeat_task,
@@ -554,14 +557,14 @@ impl RemoteClient {
             } => {
                 drop(multiplex_task);
                 drop(heartbeat_task);
-                (0, ssh_connection, delegate)
+                (0, remote_connection, delegate)
             }
             State::ReconnectFailed {
                 attempts,
-                ssh_connection,
+                remote_connection,
                 delegate,
                 ..
-            } => (attempts, ssh_connection, delegate),
+            } => (attempts, remote_connection, delegate),
             State::Connecting
             | State::Reconnecting
             | State::ReconnectExhausted
@@ -580,18 +583,21 @@ impl RemoteClient {
 
         self.set_state(State::Reconnecting, cx);
 
-        log::info!("Trying to reconnect to ssh server... Attempt {}", attempts);
+        log::info!(
+            "Trying to reconnect to remote server... Attempt {}",
+            attempts
+        );
 
         let unique_identifier = self.unique_identifier.clone();
         let client = self.client.clone();
         let reconnect_task = cx.spawn(async move |this, cx| {
             macro_rules! failed {
-                ($error:expr, $attempts:expr, $ssh_connection:expr, $delegate:expr) => {
+                ($error:expr, $attempts:expr, $remote_connection:expr, $delegate:expr) => {
                     delegate.set_status(Some(&format!("{error:#}", error = $error)), cx);
                     return State::ReconnectFailed {
                         error: anyhow!($error),
                         attempts: $attempts,
-                        ssh_connection: $ssh_connection,
+                        remote_connection: $remote_connection,
                         delegate: $delegate,
                     };
                 };
@@ -600,7 +606,7 @@ impl RemoteClient {
             if let Err(error) = remote_connection
                 .kill()
                 .await
-                .context("Failed to kill ssh process")
+                .context("Failed to kill remote_connection process")
             {
                 failed!(error, attempts, remote_connection, delegate);
             };
@@ -611,15 +617,15 @@ impl RemoteClient {
             let (incoming_tx, incoming_rx) = mpsc::unbounded::<Envelope>();
             let (connection_activity_tx, connection_activity_rx) = mpsc::channel::<()>(1);
 
-            let (ssh_connection, io_task) = match async {
-                let ssh_connection = cx
+            let (remote_connection, io_task) = match async {
+                let remote_connection = cx
                     .update_global(|pool: &mut ConnectionPool, cx| {
                         pool.connect(connection_options, delegate.clone(), cx)
                     })?
                     .await
                     .map_err(|error| error.cloned())?;
 
-                let io_task = ssh_connection.start_proxy(
+                let io_task = remote_connection.start_proxy(
                     unique_identifier,
                     true,
                     incoming_tx,
@@ -628,11 +634,11 @@ impl RemoteClient {
                     delegate.clone(),
                     cx,
                 );
-                anyhow::Ok((ssh_connection, io_task))
+                anyhow::Ok((remote_connection, io_task))
             }
             .await
             {
-                Ok((ssh_connection, io_task)) => (ssh_connection, io_task),
+                Ok((remote_connection, io_task)) => (remote_connection, io_task),
                 Err(error) => {
                     failed!(error, attempts, remote_connection, delegate);
                 }
@@ -642,11 +648,11 @@ impl RemoteClient {
             client.reconnect(incoming_rx, outgoing_tx, cx);
 
             if let Err(error) = client.resync(HEARTBEAT_TIMEOUT).await {
-                failed!(error, attempts, ssh_connection, delegate);
+                failed!(error, attempts, remote_connection, delegate);
             };
 
             State::Connected {
-                remote_connection: ssh_connection,
+                remote_connection: remote_connection,
                 delegate,
                 multiplex_task,
                 heartbeat_task: Self::heartbeat(this.clone(), connection_activity_rx, cx),
@@ -706,7 +712,7 @@ impl RemoteClient {
         cx: &mut AsyncApp,
     ) -> Task<Result<()>> {
         let Ok(client) = this.read_with(cx, |this, _| this.client.clone()) else {
-            return Task::ready(Err(anyhow!("SshRemoteClient lost")));
+            return Task::ready(Err(anyhow!("remote_connectionRemoteClient lost")));
         };
 
         cx.spawn(async move |cx| {
@@ -719,7 +725,7 @@ impl RemoteClient {
                 select_biased! {
                     result = connection_activity_rx.next().fuse() => {
                         if result.is_none() {
-                            log::warn!("ssh heartbeat: connection activity channel has been dropped. stopping.");
+                            log::warn!("remote heartbeat: connection activity channel has been dropped. stopping.");
                             return Ok(());
                         }
 
@@ -826,7 +832,10 @@ impl RemoteClient {
                     }
                 }
                 Err(error) => {
-                    log::warn!("ssh io task died with error: {:?}. reconnecting...", error);
+                    log::warn!(
+                        "remote io task died with error: {:?}. reconnecting...",
+                        error
+                    );
                     this.update(cx, |this, cx| {
                         this.reconnect(cx).ok();
                     })?;
@@ -884,7 +893,7 @@ impl RemoteClient {
         port_forward: Option<(u16, String, u16)>,
     ) -> Result<CommandTemplate> {
         let Some(connection) = self.remote_connection() else {
-            return Err(anyhow!("no ssh connection"));
+            return Err(anyhow!("no remote connection"));
         };
         connection.build_command(program, args, env, working_dir, port_forward)
     }
@@ -894,7 +903,7 @@ impl RemoteClient {
         forwards: Vec<(u16, String, u16)>,
     ) -> Result<CommandTemplate> {
         let Some(connection) = self.remote_connection() else {
-            return Err(anyhow!("no ssh connection"));
+            return Err(anyhow!("no remote connection"));
         };
         connection.build_forward_ports_command(forwards)
     }
@@ -906,7 +915,7 @@ impl RemoteClient {
         cx: &App,
     ) -> Task<Result<()>> {
         let Some(connection) = self.remote_connection() else {
-            return Task::ready(Err(anyhow!("no ssh connection")));
+            return Task::ready(Err(anyhow!("no remote connection")));
         };
         connection.upload_directory(src_path, dest_path, cx)
     }
@@ -1067,11 +1076,11 @@ impl ConnectionPool {
                 );
                 return task.clone();
             }
-            Some(ConnectionPoolEntry::Connected(ssh)) => {
-                if let Some(ssh) = ssh.upgrade()
-                    && !ssh.has_been_killed()
+            Some(ConnectionPoolEntry::Connected(remote)) => {
+                if let Some(remote) = remote.upgrade()
+                    && !remote.has_been_killed()
                 {
-                    return Task::ready(Ok(ssh)).shared();
+                    return Task::ready(Ok(remote)).shared();
                 }
                 self.connections.remove(&opts);
             }
@@ -1314,7 +1323,7 @@ impl ChannelClient {
                 if let Some(proto::envelope::Payload::FlushBufferedMessages(_)) = &incoming.payload
                 {
                     log::debug!(
-                        "{}:ssh message received. name:FlushBufferedMessages",
+                        "{}:remote message received. name:FlushBufferedMessages",
                         this.name
                     );
                     {
@@ -1363,13 +1372,13 @@ impl ChannelClient {
                         this.clone().into(),
                         cx.clone(),
                     ) {
-                        log::debug!("{}:ssh message received. name:{type_name}", this.name);
+                        log::debug!("{}:remote message received. name:{type_name}", this.name);
                         cx.foreground_executor()
                             .spawn(async move {
                                 match future.await {
                                     Ok(_) => {
                                         log::debug!(
-                                            "{}:ssh message handled. name:{type_name}",
+                                            "{}:remote message handled. name:{type_name}",
                                             this.name
                                         );
                                     }
@@ -1394,7 +1403,7 @@ impl ChannelClient {
                             })
                             .detach()
                     } else {
-                        log::error!("{}:unhandled ssh message name:{type_name}", this.name);
+                        log::error!("{}:unhandled remote message name:{type_name}", this.name);
                         if let Err(e) = AnyProtoClient::from(this.clone()).send_response(
                             message_id,
                             anyhow::anyhow!("no handler registered for {type_name}").to_proto(),
@@ -1433,12 +1442,12 @@ impl ChannelClient {
         payload: T,
         use_buffer: bool,
     ) -> impl 'static + Future<Output = Result<T::Response>> {
-        log::debug!("ssh request start. name:{}", T::NAME);
+        log::debug!("remote request start. name:{}", T::NAME);
         let response =
             self.request_dynamic(payload.into_envelope(0, None, None), T::NAME, use_buffer);
         async move {
             let response = response.await?;
-            log::debug!("ssh request finish. name:{}", T::NAME);
+            log::debug!("remote request finish. name:{}", T::NAME);
             T::Response::from_envelope(response).context("received a response of the wrong type")
         }
     }
@@ -1480,7 +1489,7 @@ impl ChannelClient {
     }
 
     fn send<T: EnvelopedMessage>(&self, payload: T) -> Result<()> {
-        log::debug!("ssh send name:{}", T::NAME);
+        log::debug!("remote send name:{}", T::NAME);
         self.send_dynamic(payload.into_envelope(0, None, None))
     }
 

crates/remote/src/transport/docker.rs 🔗

@@ -24,8 +24,8 @@ use gpui::{App, AppContext, AsyncApp, Task};
 use rpc::proto::Envelope;
 
 use crate::{
-    RemoteArch, RemoteClientDelegate, RemoteConnection, RemoteConnectionOptions, RemoteOs,
-    RemotePlatform, remote_client::CommandTemplate,
+    RemoteClientDelegate, RemoteConnection, RemoteConnectionOptions, RemoteOs, RemotePlatform,
+    remote_client::CommandTemplate, transport::parse_platform,
 };
 
 #[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
@@ -119,33 +119,7 @@ impl DockerExecConnection {
         let uname = self
             .run_docker_exec("uname", None, &Default::default(), &["-sm"])
             .await?;
-        let Some((os, arch)) = uname.split_once(" ") else {
-            anyhow::bail!("unknown uname: {uname:?}")
-        };
-
-        let os = match os.trim() {
-            "Darwin" => RemoteOs::MacOs,
-            "Linux" => RemoteOs::Linux,
-            _ => anyhow::bail!(
-                "Prebuilt remote servers are not yet available for {os:?}. See https://zed.dev/docs/remote-development"
-            ),
-        };
-        // exclude armv5,6,7 as they are 32-bit.
-        let arch = if arch.starts_with("armv8")
-            || arch.starts_with("armv9")
-            || arch.starts_with("arm64")
-            || arch.starts_with("aarch64")
-        {
-            RemoteArch::Aarch64
-        } else if arch.starts_with("x86") {
-            RemoteArch::X86_64
-        } else {
-            anyhow::bail!(
-                "Prebuilt remote servers are not yet available for {arch:?}. See https://zed.dev/docs/remote-development"
-            )
-        };
-
-        Ok(RemotePlatform { os, arch })
+        parse_platform(&uname)
     }
 
     async fn ensure_server_binary(

crates/remote_server/Cargo.toml 🔗

@@ -27,6 +27,7 @@ askpass.workspace = true
 clap.workspace = true
 client.workspace = true
 collections.workspace = true
+crashes.workspace = true
 dap_adapters.workspace = true
 debug_adapter_extension.workspace = true
 env_logger.workspace = true
@@ -71,7 +72,6 @@ thiserror.workspace = true
 rayon.workspace = true
 
 [target.'cfg(not(windows))'.dependencies]
-crashes.workspace = true
 crash-handler.workspace = true
 fork.workspace = true
 libc.workspace = true

crates/remote_server/src/headless_project.rs 🔗

@@ -462,7 +462,11 @@ impl HeadlessProject {
                             .with_tag("path", path.to_string_lossy().as_ref())
                     )
                 })?;
-                parent.join(path.file_name().unwrap())
+                if let Some(file_name) = path.file_name() {
+                    parent.join(file_name)
+                } else {
+                    parent
+                }
             }
         };
 

crates/remote_server/src/main.rs 🔗

@@ -1,5 +1,3 @@
-#![cfg_attr(target_os = "windows", allow(unused, dead_code))]
-
 use clap::Parser;
 use remote_server::Commands;
 use std::path::PathBuf;
@@ -22,12 +20,6 @@ struct Cli {
     printenv: bool,
 }
 
-#[cfg(windows)]
-fn main() {
-    unimplemented!()
-}
-
-#[cfg(not(windows))]
 fn main() -> anyhow::Result<()> {
     let cli = Cli::parse();
 
@@ -46,10 +38,20 @@ fn main() -> anyhow::Result<()> {
         return Ok(());
     }
 
+    #[cfg(not(windows))]
     if let Some(command) = cli.command {
         remote_server::run(command)
     } else {
         eprintln!("usage: remote <run|proxy|version>");
         std::process::exit(1);
     }
+
+    #[cfg(windows)]
+    if let Some(_) = cli.command {
+        eprintln!("run is not supported on Windows");
+        std::process::exit(2);
+    } else {
+        eprintln!("usage: remote <run|proxy|version>");
+        std::process::exit(1);
+    }
 }

crates/remote_server/src/unix.rs 🔗

@@ -717,6 +717,9 @@ pub(crate) enum SpawnServerError {
 
     #[error("failed to launch and detach server process: {status}\n{paths}")]
     LaunchStatus { status: ExitStatus, paths: String },
+
+    #[error("failed to wait for server to be ready to accept connections")]
+    Timeout,
 }
 
 async fn spawn_server(paths: &ServerPaths) -> Result<(), SpawnServerError> {
@@ -769,6 +772,9 @@ async fn spawn_server(paths: &ServerPaths) -> Result<(), SpawnServerError> {
         log::debug!("waiting for server to be ready to accept connections...");
         std::thread::sleep(wait_duration);
         total_time_waited += wait_duration;
+        if total_time_waited > std::time::Duration::from_secs(10) {
+            return Err(SpawnServerError::Timeout);
+        }
     }
 
     log::info!(

crates/workspace/src/workspace.rs 🔗

@@ -1321,7 +1321,7 @@ impl Workspace {
                     }
                 }
 
-                project::Event::DisconnectedFromSshRemote => {
+                project::Event::DisconnectedFromRemote => {
                     this.update_window_edited(window, cx);
                 }
 

crates/zed/src/main.rs 🔗

@@ -33,7 +33,7 @@ use assets::Assets;
 use node_runtime::{NodeBinaryOptions, NodeRuntime};
 use parking_lot::Mutex;
 use project::{project_settings::ProjectSettings, trusted_worktrees};
-use recent_projects::{SshSettings, open_remote_project};
+use recent_projects::{RemoteSettings, open_remote_project};
 use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
 use session::{AppSession, Session};
 use settings::{BaseKeymap, Settings, SettingsStore, watch_config_file};
@@ -1187,7 +1187,7 @@ async fn restore_or_create_workspace(app_state: Arc<AppState>, cx: &mut AsyncApp
                     let app_state = app_state.clone();
                     if let RemoteConnectionOptions::Ssh(options) = &mut connection_options {
                         cx.update(|cx| {
-                            SshSettings::get_global(cx)
+                            RemoteSettings::get_global(cx)
                                 .fill_connection_options_from_settings(options)
                         })?;
                     }

crates/zed/src/zed/open_listener.rs 🔗

@@ -18,7 +18,7 @@ use gpui::{App, AsyncApp, Global, WindowHandle};
 use language::Point;
 use onboarding::FIRST_OPEN;
 use onboarding::show_onboarding_view;
-use recent_projects::{SshSettings, open_remote_project};
+use recent_projects::{RemoteSettings, open_remote_project};
 use remote::{RemoteConnectionOptions, WslConnectionOptions};
 use settings::Settings;
 use std::path::{Path, PathBuf};
@@ -204,7 +204,7 @@ impl OpenRequest {
             "cannot open both local and ssh paths"
         );
         let mut connection_options =
-            SshSettings::get_global(cx).connection_options_for(host, port, username);
+            RemoteSettings::get_global(cx).connection_options_for(host, port, username);
         if let Some(password) = url.password() {
             connection_options.password = Some(password.to_string());
         }
@@ -516,7 +516,7 @@ async fn open_workspaces(
                     let app_state = app_state.clone();
                     if let RemoteConnectionOptions::Ssh(options) = &mut connection {
                         cx.update(|cx| {
-                            SshSettings::get_global(cx)
+                            RemoteSettings::get_global(cx)
                                 .fill_connection_options_from_settings(options)
                         })?;
                     }