diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 7935b451b7..c1752a481f 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -4,8 +4,10 @@ use anyhow::{Context, Result}; use clap::Parser; use cli::{ipc::IpcOneShotServer, CliRequest, CliResponse, IpcHandshake}; use std::{ - env, fs, + env, fs, io, path::{Path, PathBuf}, + process::ExitStatus, + thread::{self, JoinHandle}, }; use util::paths::PathLikeWithPosition; @@ -14,6 +16,7 @@ struct Detect; trait InstalledApp { fn zed_version_string(&self) -> String; fn launch(&self, ipc_url: String) -> anyhow::Result<()>; + fn run_foreground(&self, ipc_url: String) -> io::Result; } #[derive(Parser, Debug)] @@ -37,6 +40,9 @@ struct Args { /// Print Zed's version and the app path. #[arg(short, long)] version: bool, + /// Run zed in the foreground (useful for debugging) + #[arg(long)] + foreground: bool, /// Custom path to Zed.app or the zed binary #[arg(long)] zed: Option, @@ -99,10 +105,6 @@ fn main() -> Result<()> { IpcOneShotServer::::new().context("Handshake before Zed spawn")?; let url = format!("zed-cli://{server_name}"); - app.launch(url)?; - let (_, handshake) = server.accept().context("Handshake after Zed spawn")?; - let (tx, rx) = (handshake.requests, handshake.responses); - let open_new_workspace = if args.new { Some(true) } else if args.add { @@ -111,20 +113,33 @@ fn main() -> Result<()> { None }; - tx.send(CliRequest::Open { - paths, - wait: args.wait, - open_new_workspace, - dev_server_token: args.dev_server_token, - })?; + let sender: JoinHandle> = thread::spawn(move || { + let (_, handshake) = server.accept().context("Handshake after Zed spawn")?; + let (tx, rx) = (handshake.requests, handshake.responses); + tx.send(CliRequest::Open { + paths, + wait: args.wait, + open_new_workspace, + dev_server_token: args.dev_server_token, + })?; - while let Ok(response) = rx.recv() { - match response { - CliResponse::Ping => {} - CliResponse::Stdout { message } => println!("{message}"), - CliResponse::Stderr { message } => eprintln!("{message}"), - CliResponse::Exit { status } => std::process::exit(status), + while let Ok(response) = rx.recv() { + match response { + CliResponse::Ping => {} + CliResponse::Stdout { message } => println!("{message}"), + CliResponse::Stderr { message } => eprintln!("{message}"), + CliResponse::Exit { status } => std::process::exit(status), + } } + + Ok(()) + }); + + if args.foreground { + app.run_foreground(url)?; + } else { + app.launch(url)?; + sender.join().unwrap()?; } Ok(()) @@ -141,7 +156,8 @@ mod linux { unix::net::{SocketAddr, UnixDatagram}, }, path::{Path, PathBuf}, - process, thread, + process::{self, ExitStatus}, + thread, time::Duration, }; @@ -208,6 +224,12 @@ mod linux { } Ok(()) } + + fn run_foreground(&self, ipc_url: String) -> io::Result { + std::process::Command::new(self.0.clone()) + .arg(ipc_url) + .status() + } } impl App { @@ -257,7 +279,9 @@ mod linux { #[cfg(target_os = "windows")] mod windows { use crate::{Detect, InstalledApp}; + use std::io; use std::path::Path; + use std::process::ExitStatus; struct App; impl InstalledApp for App { @@ -267,6 +291,9 @@ mod windows { fn launch(&self, _ipc_url: String) -> anyhow::Result<()> { unimplemented!() } + fn run_foreground(&self, _ipc_url: String) -> io::Result { + unimplemented!() + } } impl Detect { @@ -288,9 +315,9 @@ mod mac_os { use serde::Deserialize; use std::{ ffi::OsStr, - fs, + fs, io, path::{Path, PathBuf}, - process::Command, + process::{Command, ExitStatus}, ptr, }; @@ -442,6 +469,15 @@ mod mac_os { Ok(()) } + + fn run_foreground(&self, ipc_url: String) -> io::Result { + let path = match self { + Bundle::App { app_bundle, .. } => app_bundle.join("Contents/MacOS/zed"), + Bundle::LocalPath { executable, .. } => executable.clone(), + }; + + std::process::Command::new(path).arg(ipc_url).status() + } } impl Bundle { diff --git a/docs/src/remote-development.md b/docs/src/remote-development.md index 5e8341512c..76817645ab 100644 --- a/docs/src/remote-development.md +++ b/docs/src/remote-development.md @@ -12,7 +12,7 @@ Currently the two instances connect via Zed's servers, but we intend to build pe ## Setup -> **Note**: You must be in the alpha program to see this UI. The instructions will likely change as the feature gets closer to launch. +> NOTE: You must be in the alpha program to see this UI. The instructions will likely change as the feature gets closer to launch. 1. Open the projects dialog with `cmd-option-o` and then click "Connect…". 2. Click "Add Server" @@ -21,20 +21,26 @@ Currently the two instances connect via Zed's servers, but we intend to build pe ``` curl https://zed.dev/install.sh | bash ``` -5. On the remote machine, paste the instructions from step 3. - - > **Note**: Currently you must keep this process open. We are working on making it background itself. - > In the meantime, you can run `nohup zed --dev-server-token YY.XXX >~/.zed-log 2>&1 &` - +5. On the remote machine, paste the instructions from step 3. You should see `connected!`. + > NOTE: If this command runs but doesn't output anything, try running `zed --foreground --dev-server-token YY.XXX`. It is possible that the zed background process is crashing on startup. 6. On your laptop you can now open folders on the remote machine. - > **Note**: Zed does not currently handle opening very large directories (e.g. `/` or `~` that may have >100,000 files) very well. We are working on improving this, but suggest in the meantime opening only specific projects, or subfolders of very large mono-repos. + > NOTE: Zed does not currently handle opening very large directories (e.g. `/` or `~` that may have >100,000 files) very well. We are working on improving this, but suggest in the meantime opening only specific projects, or subfolders of very large mono-repos. + +## Supported platforms + +The remote machine must be able to run Zed. The following platforms should work, though note that we have not exhaustively tested every linux distribution: + +* macOS Catalina or later (Intel or Apple Silicon)) +* Linux (x86_64 only). You must have `glibc` installed at version 2.29 (released in 2019) or greater and available globally. +* Windows is not yet supported. ## Known Limitations - The Terminal does not work remotely. - You cannot spawn Tasks remotely. - Extensions aren't yet supported in headless Zed. +- You can not run `zed` in headless mode and in GUI mode at the same time on the same machine. ## Feedback -- Please join the [#remoting-feedback](https://discord.com/channels/869392257814519848/1235290452270387241) Discord channel. +- Please join the #remoting-feedback in the [Zed Discord](https://discord.gg/qSDQ8VWc7k).