This PR provides some of the plumbing needed for a "remote" zed
instance.

The way this will work is:
* From zed on your laptop you'll be able to manage a set of dev servers,
each of which is identified by a token.
* You'll run `zed --dev-server-token XXXX` to boot a remotable dev
server.
* From the zed on your laptop you'll be able to open directories and
work on the projects on the remote server (exactly like collaboration
works today).

For now all this PR does is provide the ability for a zed instance to
sign in
using a "dev server token". The next steps will be:
* Adding support to the collaboration protocol to instruct a dev server
to "open" a directory and share it into a channel.
* Adding UI to manage these servers and tokens (manually for now)

Related #5347

Release Notes:

- N/A

---------

Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
Conrad Irwin 2024-03-22 08:44:56 -06:00 committed by GitHub
parent f56707e076
commit cb4f868815
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 582 additions and 296 deletions

View file

@ -26,6 +26,7 @@ breadcrumbs.workspace = true
call.workspace = true
channel.workspace = true
chrono.workspace = true
clap.workspace = true
cli.workspace = true
client.workspace = true
clock.workspace = true

View file

@ -6,8 +6,9 @@ mod zed;
use anyhow::{anyhow, Context as _, Result};
use backtrace::Backtrace;
use chrono::Utc;
use clap::{command, Parser};
use cli::FORCE_CLI_MODE_ENV_VAR_NAME;
use client::{parse_zed_link, Client, UserStore};
use client::{parse_zed_link, Client, ClientSettings, DevServerToken, UserStore};
use collab_ui::channel_view::ChannelView;
use db::kvp::KEY_VALUE_STORE;
use editor::Editor;
@ -270,9 +271,28 @@ fn main() {
cx.activate(true);
let urls = collect_url_args(cx);
if !urls.is_empty() {
listener.open_urls(urls)
let mut args = Args::parse();
if let Some(dev_server_token) = args.dev_server_token.take() {
let dev_server_token = DevServerToken(dev_server_token);
let server_url = ClientSettings::get_global(&cx).server_url.clone();
let client = client.clone();
client.set_dev_server_token(dev_server_token);
cx.spawn(|cx| async move {
client.authenticate_and_connect(false, &cx).await?;
log::info!("Connected to {}", server_url);
anyhow::Ok(())
})
.detach_and_log_err(cx);
} else {
let urls: Vec<_> = args
.paths_or_urls
.iter()
.filter_map(|arg| parse_url_arg(arg, cx).log_err())
.collect();
if !urls.is_empty() {
listener.open_urls(urls)
}
}
let mut triggered_authentication = false;
@ -898,23 +918,35 @@ fn stdout_is_a_pty() -> bool {
std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_none() && std::io::stdout().is_terminal()
}
fn collect_url_args(cx: &AppContext) -> Vec<String> {
env::args()
.skip(1)
.filter_map(|arg| match std::fs::canonicalize(Path::new(&arg)) {
Ok(path) => Some(format!("file://{}", path.to_string_lossy())),
Err(error) => {
if arg.starts_with("file://") || arg.starts_with("zed-cli://") {
Some(arg)
} else if let Some(_) = parse_zed_link(&arg, cx) {
Some(arg)
} else {
log::error!("error parsing path argument: {}", error);
None
}
#[derive(Parser, Debug)]
#[command(name = "zed", disable_version_flag = true)]
struct Args {
/// A sequence of space-separated paths or urls that you want to open.
///
/// Use `path:line:row` syntax to open a file at a specific location.
/// Non-existing paths and directories will ignore `:line:row` suffix.
///
/// URLs can either be file:// or zed:// scheme, or relative to https://zed.dev.
paths_or_urls: Vec<String>,
/// Instructs zed to run as a dev server on this machine. (not implemented)
#[arg(long)]
dev_server_token: Option<String>,
}
fn parse_url_arg(arg: &str, cx: &AppContext) -> Result<String> {
match std::fs::canonicalize(Path::new(&arg)) {
Ok(path) => Ok(format!("file://{}", path.to_string_lossy())),
Err(error) => {
if arg.starts_with("file://") || arg.starts_with("zed-cli://") {
Ok(arg.into())
} else if let Some(_) = parse_zed_link(&arg, cx) {
Ok(arg.into())
} else {
Err(anyhow!("error parsing path argument: {}", error))
}
})
.collect()
}
}
}
fn load_embedded_fonts(cx: &AppContext) {