Start work on connecting to RPC endpoint

Max Brunsfeld and Antonio Scandurra created

Co-Authored-By: Antonio Scandurra <me@as-cii.com>

Change summary

Cargo.lock          | 676 ++++++++++++++++++++++++++++++++++++++++++++--
gpui/src/app.rs     |   6 
zed-rpc/Cargo.toml  |   1 
zed-rpc/src/lib.rs  |   1 
zed-rpc/src/rest.rs |   7 
zed/Cargo.toml      |   2 
zed/src/lib.rs      | 196 ++++++++-----
zed/src/menus.rs    |   4 
zed/src/util.rs     |  30 ++
9 files changed, 798 insertions(+), 125 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -21,6 +21,60 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
 
+[[package]]
+name = "aead"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "aes"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561"
+dependencies = [
+ "aes-soft",
+ "aesni",
+ "cipher",
+]
+
+[[package]]
+name = "aes-gcm"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da"
+dependencies = [
+ "aead",
+ "aes",
+ "cipher",
+ "ctr",
+ "ghash",
+ "subtle",
+]
+
+[[package]]
+name = "aes-soft"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072"
+dependencies = [
+ "cipher",
+ "opaque-debug",
+]
+
+[[package]]
+name = "aesni"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce"
+dependencies = [
+ "cipher",
+ "opaque-debug",
+]
+
 [[package]]
 name = "aho-corasick"
 version = "0.7.15"
@@ -99,6 +153,22 @@ dependencies = [
  "futures-lite",
 ]
 
+[[package]]
+name = "async-global-executor"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6"
+dependencies = [
+ "async-channel",
+ "async-executor",
+ "async-io",
+ "async-mutex",
+ "blocking",
+ "futures-lite",
+ "num_cpus",
+ "once_cell",
+]
+
 [[package]]
 name = "async-io"
 version = "1.3.1"
@@ -128,6 +198,15 @@ dependencies = [
  "event-listener",
 ]
 
+[[package]]
+name = "async-mutex"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
+dependencies = [
+ "event-listener",
+]
+
 [[package]]
 name = "async-net"
 version = "1.5.0"
@@ -156,11 +235,49 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "async-std"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341"
+dependencies = [
+ "async-channel",
+ "async-global-executor",
+ "async-io",
+ "async-lock",
+ "crossbeam-utils",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-lite",
+ "gloo-timers",
+ "kv-log-macro",
+ "log",
+ "memchr",
+ "num_cpus",
+ "once_cell",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+ "wasm-bindgen-futures",
+]
+
 [[package]]
 name = "async-task"
 version = "4.0.3"
 source = "git+https://github.com/zed-industries/async-task?rev=341b57d6de98cdfd7b418567b8de2022ca993a6e#341b57d6de98cdfd7b418567b8de2022ca993a6e"
 
+[[package]]
+name = "async-trait"
+version = "0.1.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "atomic"
 version = "0.5.0"
@@ -213,6 +330,18 @@ dependencies = [
  "rustc-demangle",
 ]
 
+[[package]]
+name = "base-x"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
+
+[[package]]
+name = "base64"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
+
 [[package]]
 name = "base64"
 version = "0.13.0"
@@ -271,6 +400,15 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
 
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "blocking"
 version = "1.0.2"
@@ -294,6 +432,12 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "bumpalo"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631"
+
 [[package]]
 name = "bytemuck"
 version = "1.5.1"
@@ -306,6 +450,12 @@ version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
 
+[[package]]
+name = "bytes"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
+
 [[package]]
 name = "bytes"
 version = "1.0.1"
@@ -404,10 +554,19 @@ dependencies = [
  "libc",
  "num-integer",
  "num-traits 0.2.14",
- "time",
+ "time 0.1.44",
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "cipher"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "clang-sys"
 version = "1.1.1"
@@ -496,12 +655,35 @@ dependencies = [
  "cache-padded",
 ]
 
+[[package]]
+name = "const_fn"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7"
+
 [[package]]
 name = "constant_time_eq"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
 
+[[package]]
+name = "cookie"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951"
+dependencies = [
+ "aes-gcm",
+ "base64 0.13.0",
+ "hkdf",
+ "hmac",
+ "percent-encoding",
+ "rand 0.8.3",
+ "sha2",
+ "time 0.2.25",
+ "version_check",
+]
+
 [[package]]
 name = "core-foundation"
 version = "0.9.1"
@@ -551,6 +733,21 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "cpufeatures"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cpuid-bool"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba"
+
 [[package]]
 name = "crc32fast"
 version = "1.2.1"
@@ -617,6 +814,16 @@ dependencies = [
  "loom",
 ]
 
+[[package]]
+name = "crypto-mac"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6"
+dependencies = [
+ "generic-array",
+ "subtle",
+]
+
 [[package]]
 name = "ctor"
 version = "0.1.20"
@@ -627,6 +834,62 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "ctr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "curl"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "003cb79c1c6d1c93344c7e1201bb51c2148f24ec2bd9c253709d6b2efb796515"
+dependencies = [
+ "curl-sys",
+ "libc",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "socket2 0.4.0",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "curl-sys"
+version = "0.4.44+curl-7.77.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b6d85e9322b193f117c966e79c2d6929ec08c02f339f950044aba12e20bbaf1"
+dependencies = [
+ "cc",
+ "libc",
+ "libnghttp2-sys",
+ "libz-sys",
+ "openssl-sys",
+ "pkg-config",
+ "vcpkg",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "dashmap"
+version = "4.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
+dependencies = [
+ "cfg-if 1.0.0",
+ "num_cpus",
+]
+
+[[package]]
+name = "data-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
+
 [[package]]
 name = "data-url"
 version = "0.1.0"
@@ -717,6 +980,12 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "discard"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
+
 [[package]]
 name = "dtoa"
 version = "0.4.8"
@@ -811,6 +1080,15 @@ version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
 
+[[package]]
+name = "encoding_rs"
+version = "0.8.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
 [[package]]
 name = "enum_primitive"
 version = "0.1.1"
@@ -929,6 +1207,17 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e"
 
+[[package]]
+name = "flume"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bebadab126f8120d410b677ed95eee4ba6eb7c6dd8e34a5ec88a08050e26132"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "spinning_top",
+]
+
 [[package]]
 name = "fnv"
 version = "1.0.7"
@@ -1092,6 +1381,18 @@ dependencies = [
  "waker-fn",
 ]
 
+[[package]]
+name = "futures-macro"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "futures-sink"
 version = "0.3.14"
@@ -1111,10 +1412,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b"
 dependencies = [
  "futures-core",
+ "futures-io",
+ "futures-macro",
  "futures-sink",
  "futures-task",
+ "memchr",
  "pin-project-lite",
  "pin-utils",
+ "proc-macro-hack",
+ "proc-macro-nested",
+ "slab",
 ]
 
 [[package]]
@@ -1162,6 +1469,16 @@ dependencies = [
  "wasi 0.10.0+wasi-snapshot-preview1",
 ]
 
+[[package]]
+name = "ghash"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375"
+dependencies = [
+ "opaque-debug",
+ "polyval",
+]
+
 [[package]]
 name = "gif"
 version = "0.9.2"
@@ -1203,6 +1520,19 @@ dependencies = [
  "regex",
 ]
 
+[[package]]
+name = "gloo-timers"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "gpui"
 version = "0.1.0"
@@ -1280,60 +1610,137 @@ dependencies = [
 ]
 
 [[package]]
-name = "humantime"
-version = "2.1.0"
+name = "hkdf"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f"
+dependencies = [
+ "digest",
+ "hmac",
+]
 
 [[package]]
-name = "icns"
-version = "0.2.2"
+name = "hmac"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b324f19f93365e45c7375968a81ff3c52dd99893a48b886099d1664df6d38e68"
+checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
 dependencies = [
- "byteorder",
- "png 0.11.0",
+ "crypto-mac",
+ "digest",
 ]
 
 [[package]]
-name = "idna"
-version = "0.2.3"
+name = "http"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
+checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
 dependencies = [
- "matches",
- "unicode-bidi",
- "unicode-normalization",
+ "bytes 1.0.1",
+ "fnv",
+ "itoa 0.4.7",
 ]
 
 [[package]]
-name = "ignore"
-version = "0.4.17"
+name = "http-auth-basic"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c"
+checksum = "df69b6a68474b935f436fb9c84139f32de4f7759810090d1a3a5e592553f7ee0"
 dependencies = [
- "crossbeam-utils",
- "globset",
- "lazy_static",
- "log",
- "memchr",
- "regex",
- "same-file",
- "thread_local",
- "walkdir",
- "winapi-util",
+ "base64 0.12.3",
 ]
 
 [[package]]
-name = "image"
-version = "0.12.4"
+name = "http-client"
+version = "6.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d95816db758249fe16f23a4e23f1a3a817fe11892dbfd1c5836f625324702158"
+checksum = "ce318d86a47d18d1db645c979214f809a6cd625202ad334ef75ca813b30dac80"
 dependencies = [
- "byteorder",
- "enum_primitive",
- "gif",
- "jpeg-decoder",
+ "async-std",
+ "async-trait",
+ "cfg-if 1.0.0",
+ "dashmap",
+ "http-types",
+ "isahc",
+ "log",
+]
+
+[[package]]
+name = "http-types"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad077d89137cd3debdce53c66714dc536525ef43fe075d41ddc0a8ac11f85957"
+dependencies = [
+ "anyhow",
+ "async-channel",
+ "async-std",
+ "base64 0.13.0",
+ "cookie",
+ "futures-lite",
+ "infer",
+ "pin-project-lite",
+ "rand 0.7.3",
+ "serde 1.0.125",
+ "serde_json 1.0.64",
+ "serde_qs",
+ "serde_urlencoded",
+ "url",
+]
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "icns"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b324f19f93365e45c7375968a81ff3c52dd99893a48b886099d1664df6d38e68"
+dependencies = [
+ "byteorder",
+ "png 0.11.0",
+]
+
+[[package]]
+name = "idna"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
+dependencies = [
+ "matches",
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "ignore"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c"
+dependencies = [
+ "crossbeam-utils",
+ "globset",
+ "lazy_static",
+ "log",
+ "memchr",
+ "regex",
+ "same-file",
+ "thread_local",
+ "walkdir",
+ "winapi-util",
+]
+
+[[package]]
+name = "image"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d95816db758249fe16f23a4e23f1a3a817fe11892dbfd1c5836f625324702158"
+dependencies = [
+ "byteorder",
+ "enum_primitive",
+ "gif",
+ "jpeg-decoder",
  "num-iter",
  "num-rational",
  "num-traits 0.1.43",
@@ -1351,6 +1758,12 @@ dependencies = [
  "hashbrown",
 ]
 
+[[package]]
+name = "infer"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
+
 [[package]]
 name = "inflate"
 version = "0.1.1"
@@ -1375,6 +1788,29 @@ dependencies = [
  "cfg-if 1.0.0",
 ]
 
+[[package]]
+name = "isahc"
+version = "0.9.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a"
+dependencies = [
+ "bytes 0.5.6",
+ "crossbeam-utils",
+ "curl",
+ "curl-sys",
+ "flume",
+ "futures-lite",
+ "http",
+ "log",
+ "once_cell",
+ "slab",
+ "sluice",
+ "tracing",
+ "tracing-futures",
+ "url",
+ "waker-fn",
+]
+
 [[package]]
 name = "itertools"
 version = "0.9.0"
@@ -1414,6 +1850,15 @@ dependencies = [
  "rayon",
 ]
 
+[[package]]
+name = "js-sys"
+version = "0.3.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
+dependencies = [
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "kernel32-sys"
 version = "0.2.2"
@@ -1433,6 +1878,15 @@ dependencies = [
  "arrayvec",
 ]
 
+[[package]]
+name = "kv-log-macro"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
+dependencies = [
+ "log",
+]
+
 [[package]]
 name = "lazy_static"
 version = "1.4.0"
@@ -1482,6 +1936,28 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
 
+[[package]]
+name = "libnghttp2-sys"
+version = "0.1.6+1.43.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0af55541a8827e138d59ec9e5877fb6095ece63fb6f4da45e7491b4fbd262855"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "libz-sys"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
 [[package]]
 name = "lock_api"
 version = "0.4.2"
@@ -1498,6 +1974,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
 dependencies = [
  "cfg-if 1.0.0",
+ "value-bag",
 ]
 
 [[package]]
@@ -1585,6 +2062,22 @@ dependencies = [
  "objc",
 ]
 
+[[package]]
+name = "mime"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
 [[package]]
 name = "miniz_oxide"
 version = "0.3.7"
@@ -1629,7 +2122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f"
 dependencies = [
  "libc",
- "socket2",
+ "socket2 0.3.19",
 ]
 
 [[package]]
@@ -1762,6 +2255,31 @@ version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
 
+[[package]]
+name = "opaque-debug"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98"
+dependencies = [
+ "autocfg 1.0.1",
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
 [[package]]
 name = "ordered-float"
 version = "2.1.1"
@@ -1842,7 +2360,7 @@ version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb"
 dependencies = [
- "base64",
+ "base64 0.13.0",
  "once_cell",
  "regex",
 ]
@@ -2000,6 +2518,17 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6cce106fd2646acbe31a0e4006f75779d535c26a44f153ada196e9edcfc6d944"
 
+[[package]]
+name = "polyval"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd"
+dependencies = [
+ "cpuid-bool",
+ "opaque-debug",
+ "universal-hash",
+]
+
 [[package]]
 name = "postage"
 version = "0.4.1"
@@ -2022,6 +2551,18 @@ version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
 
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
+[[package]]
+name = "proc-macro-nested"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
+
 [[package]]
 name = "proc-macro2"
 version = "1.0.24"
@@ -2037,7 +2578,7 @@ version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9e6984d2f1a23009bd270b8bb56d0926810a3d483f59c987d77969e9d8e840b2"
 dependencies = [
- "bytes",
+ "bytes 1.0.1",
  "prost-derive 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2046,7 +2587,7 @@ name = "prost"
 version = "0.7.0"
 source = "git+https://github.com/sfackler/prost?rev=082f3e65874fe91382e72482863896b7b4db3728#082f3e65874fe91382e72482863896b7b4db3728"
 dependencies = [
- "bytes",
+ "bytes 1.0.1",
  "prost-derive 0.7.0 (git+https://github.com/sfackler/prost?rev=082f3e65874fe91382e72482863896b7b4db3728)",
 ]
 
@@ -2055,7 +2596,7 @@ name = "prost-build"
 version = "0.7.0"
 source = "git+https://github.com/sfackler/prost?rev=082f3e65874fe91382e72482863896b7b4db3728#082f3e65874fe91382e72482863896b7b4db3728"
 dependencies = [
- "bytes",
+ "bytes 1.0.1",
  "heck",
  "itertools 0.10.1",
  "log",
@@ -2097,7 +2638,7 @@ name = "prost-types"
 version = "0.7.0"
 source = "git+https://github.com/sfackler/prost?rev=082f3e65874fe91382e72482863896b7b4db3728#082f3e65874fe91382e72482863896b7b4db3728"
 dependencies = [
- "bytes",
+ "bytes 1.0.1",
  "prost 0.7.0 (git+https://github.com/sfackler/prost?rev=082f3e65874fe91382e72482863896b7b4db3728)",
 ]
 
@@ -2142,6 +2683,19 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom 0.1.16",
+ "libc",
+ "rand_chacha 0.2.2",
+ "rand_core 0.5.1",
+ "rand_hc 0.2.0",
+]
+
 [[package]]
 name = "rand"
 version = "0.8.3"
@@ -2164,6 +2718,16 @@ dependencies = [
  "rand_core 0.3.1",
 ]
 
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.5.1",
+]
+
 [[package]]
 name = "rand_chacha"
 version = "0.3.0"
@@ -2189,6 +2753,15 @@ version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
 
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom 0.1.16",
+]
+
 [[package]]
 name = "rand_core"
 version = "0.6.2"
@@ -2207,6 +2780,15 @@ dependencies = [
  "rand_core 0.3.1",
 ]
 
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core 0.5.1",
+]
+
 [[package]]
 name = "rand_hc"
 version = "0.3.0"
@@ -2444,7 +3026,7 @@ version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
 dependencies = [
- "base64",
+ "base64 0.13.0",
  "blake2b_simd",
  "constant_time_eq",
  "crossbeam-utils",
@@ -2544,6 +3126,16 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "schannel"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
+dependencies = [
+ "lazy_static",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "scoped-pool"
 version = "0.0.1"

gpui/src/app.rs 🔗

@@ -2,7 +2,7 @@ use crate::{
     elements::ElementBox,
     executor,
     keymap::{self, Keystroke},
-    platform::{self, PromptLevel, WindowOptions},
+    platform::{self, Platform, PromptLevel, WindowOptions},
     presenter::Presenter,
     util::{post_inc, timeout},
     AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache,
@@ -412,6 +412,10 @@ impl AsyncAppContext {
         self.update(|cx| cx.add_model(build_model))
     }
 
+    pub fn platform(&self) -> Arc<dyn Platform> {
+        self.0.borrow().platform()
+    }
+
     pub fn background_executor(&self) -> Arc<executor::Background> {
         self.0.borrow().cx.background.clone()
     }

zed-rpc/Cargo.toml 🔗

@@ -12,6 +12,7 @@ futures-lite = "1"
 prost = "0.7"
 rsa = "0.4"
 rand = "0.8"
+serde = { version = "1", features = ["derive"] }
 
 [build-dependencies]
 prost-build = { git = "https://github.com/sfackler/prost", rev = "082f3e65874fe91382e72482863896b7b4db3728" }

zed-rpc/src/rest.rs 🔗

@@ -0,0 +1,7 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize)]
+pub struct CreateWorktreeResponse {
+    pub worktree_id: u64,
+    pub rpc_address: String,
+}

zed/Cargo.toml 🔗

@@ -23,6 +23,7 @@ easy-parallel = "3.1.0"
 fsevent = { path = "../fsevent" }
 futures-core = "0.3"
 gpui = { path = "../gpui" }
+http-auth-basic = "0.1.3"
 ignore = "0.4"
 lazy_static = "1.4.0"
 libc = "0.2"
@@ -39,6 +40,7 @@ similar = "1.3"
 simplelog = "0.9"
 smallvec = { version = "1.6", features = ["union"] }
 smol = "1.2.5"
+surf = "2.2"
 toml = "0.5"
 tree-sitter = "0.19.5"
 tree-sitter-rust = "0.19.0"

zed/src/lib.rs 🔗

@@ -1,8 +1,9 @@
-use anyhow::{anyhow, Context};
-use gpui::MutableAppContext;
+use anyhow::{anyhow, Context, Result};
+use gpui::{AsyncAppContext, MutableAppContext, Task};
 use smol::io::{AsyncBufReadExt, AsyncWriteExt};
 use std::convert::TryFrom;
 use url::Url;
+use util::SurfResultExt;
 
 pub mod assets;
 pub mod editor;
@@ -26,94 +27,129 @@ pub struct AppState {
 }
 
 pub fn init(cx: &mut MutableAppContext) {
-    cx.add_global_action("app:authenticate", authenticate);
+    cx.add_global_action("app:share_worktree", share_worktree);
     cx.add_global_action("app:quit", quit);
 }
 
-fn authenticate(_: &(), cx: &mut MutableAppContext) {
+fn share_worktree(_: &(), cx: &mut MutableAppContext) {
     let zed_url = std::env::var("ZED_SERVER_URL").unwrap_or("https://zed.dev".to_string());
-    let platform = cx.platform().clone();
+    cx.spawn::<_, _, surf::Result<()>>(|cx| async move {
+        let (user_id, access_token) = login(zed_url.clone(), cx).await?;
 
-    cx.background_executor()
-        .spawn(async move {
-            if let Some((user_id, access_token)) = platform.read_credentials(&zed_url) {
-                log::info!("already signed in. user_id: {}", user_id);
-                return Ok((user_id, String::from_utf8(access_token).unwrap()));
-            }
+        let mut response = surf::post(format!("{}/api/worktrees", &zed_url))
+            .header(
+                "Authorization",
+                http_auth_basic::Credentials::new(&user_id, &access_token).as_http_header(),
+            )
+            .await
+            .context("")?;
+
+        let body = response
+            .body_json::<zed_rpc::rest::CreateWorktreeResponse>()
+            .await?;
+
+        // TODO - If the `ZED_SERVER_URL` uses https, then wrap this stream in
+        // a TLS stream using `native-tls`.
+        let stream = smol::net::TcpStream::connect(body.rpc_address).await?;
+
+        let mut message_stream = zed_rpc::proto::MessageStream::new(stream);
+        message_stream
+            .write_message(&zed_rpc::proto::FromClient {
+                id: 0,
+                variant: Some(zed_rpc::proto::from_client::Variant::Auth(
+                    zed_rpc::proto::from_client::Auth {
+                        user_id: user_id.parse::<i32>()?,
+                        access_token,
+                    },
+                )),
+            })
+            .await?;
+
+        Ok(())
+    })
+    .detach();
+}
+
+fn login(zed_url: String, cx: AsyncAppContext) -> Task<Result<(String, String)>> {
+    let platform = cx.platform();
+    cx.background_executor().spawn(async move {
+        if let Some((user_id, access_token)) = platform.read_credentials(&zed_url) {
+            log::info!("already signed in. user_id: {}", user_id);
+            return Ok((user_id, String::from_utf8(access_token).unwrap()));
+        }
 
-            // Generate a pair of asymmetric encryption keys. The public key will be used by the
-            // zed server to encrypt the user's access token, so that it can'be intercepted by
-            // any other app running on the user's device.
-            let (public_key, private_key) =
-                zed_rpc::auth::keypair().expect("failed to generate keypair for auth");
-            let public_key_string =
-                String::try_from(public_key).expect("failed to serialize public key for auth");
-
-            // Listen on an open TCP port. This port will be used by the web browser to notify the
-            // application that the login is complete, and to send the user's id and access token.
-            let listener = smol::net::TcpListener::bind("127.0.0.1:0").await?;
-            let port = listener.local_addr()?.port();
-
-            // Open the Zed sign-in page in the user's browser, with query parameters that indicate
-            // that the user is signing in from a Zed app running on the same device.
-            platform.open_url(&format!(
-                "{}/sign_in?native_app_port={}&native_app_public_key={}",
-                zed_url, port, public_key_string
+        // Generate a pair of asymmetric encryption keys. The public key will be used by the
+        // zed server to encrypt the user's access token, so that it can'be intercepted by
+        // any other app running on the user's device.
+        let (public_key, private_key) =
+            zed_rpc::auth::keypair().expect("failed to generate keypair for auth");
+        let public_key_string =
+            String::try_from(public_key).expect("failed to serialize public key for auth");
+
+        // Listen on an open TCP port. This port will be used by the web browser to notify the
+        // application that the login is complete, and to send the user's id and access token.
+        let listener = smol::net::TcpListener::bind("127.0.0.1:0").await?;
+        let port = listener.local_addr()?.port();
+
+        // Open the Zed sign-in page in the user's browser, with query parameters that indicate
+        // that the user is signing in from a Zed app running on the same device.
+        platform.open_url(&format!(
+            "{}/sign_in?native_app_port={}&native_app_public_key={}",
+            zed_url, port, public_key_string
+        ));
+
+        // Receive the HTTP request from the user's browser. Parse the first line, which contains
+        // the HTTP method and path.
+        let (mut stream, _) = listener.accept().await?;
+        let mut reader = smol::io::BufReader::new(&mut stream);
+        let mut line = String::new();
+        reader.read_line(&mut line).await?;
+        let mut parts = line.split(" ");
+        let http_method = parts.next();
+        if http_method != Some("GET") {
+            return Err(anyhow!(
+                "unexpected http method {:?} in request from zed web app",
+                http_method
             ));
+        }
+        let path = parts.next().ok_or_else(|| {
+            anyhow!("failed to parse http request from zed login redirect - missing path")
+        })?;
 
-            // Receive the HTTP request from the user's browser. Parse the first line, which contains
-            // the HTTP method and path.
-            let (mut stream, _) = listener.accept().await?;
-            let mut reader = smol::io::BufReader::new(&mut stream);
-            let mut line = String::new();
-            reader.read_line(&mut line).await?;
-            let mut parts = line.split(" ");
-            let http_method = parts.next();
-            if http_method != Some("GET") {
-                return Err(anyhow!(
-                    "unexpected http method {:?} in request from zed web app",
-                    http_method
-                ));
-            }
-            let path = parts.next().ok_or_else(|| {
-                anyhow!("failed to parse http request from zed login redirect - missing path")
-            })?;
-
-            // Parse the query parameters from the HTTP request.
-            let mut user_id = None;
-            let mut access_token = None;
-            let url = Url::parse(&format!("http://example.com{}", path))
-                .context("failed to parse login notification url")?;
-            for (key, value) in url.query_pairs() {
-                if key == "access_token" {
-                    access_token = Some(value);
-                } else if key == "user_id" {
-                    user_id = Some(value);
-                }
+        // Parse the query parameters from the HTTP request.
+        let mut user_id = None;
+        let mut access_token = None;
+        let url = Url::parse(&format!("http://example.com{}", path))
+            .context("failed to parse login notification url")?;
+        for (key, value) in url.query_pairs() {
+            if key == "access_token" {
+                access_token = Some(value);
+            } else if key == "user_id" {
+                user_id = Some(value);
             }
+        }
+
+        // Write an HTTP response to the user's browser, instructing it to close the tab.
+        // Then transfer focus back to the application.
+        stream
+            .write_all(LOGIN_RESPONSE.as_bytes())
+            .await
+            .context("failed to write login response")?;
+        stream.flush().await.context("failed to flush tcp stream")?;
+        platform.activate(true);
+
+        // If login succeeded, then store the credentials in the keychain.
+        let user_id = user_id.ok_or_else(|| anyhow!("missing user_id in login request"))?;
+        let access_token =
+            access_token.ok_or_else(|| anyhow!("missing access_token in login request"))?;
+        let access_token = private_key
+            .decrypt_string(&access_token)
+            .context("failed to decrypt access token")?;
+        platform.write_credentials(&zed_url, &user_id, access_token.as_bytes());
+        log::info!("successfully signed in. user_id: {}", user_id);
 
-            // Write an HTTP response to the user's browser, instructing it to close the tab.
-            // Then transfer focus back to the application.
-            stream
-                .write_all(LOGIN_RESPONSE.as_bytes())
-                .await
-                .context("failed to write login response")?;
-            stream.flush().await.context("failed to flush tcp stream")?;
-            platform.activate(true);
-
-            // If login succeeded, then store the credentials in the keychain.
-            let user_id = user_id.ok_or_else(|| anyhow!("missing user_id in login request"))?;
-            let access_token =
-                access_token.ok_or_else(|| anyhow!("missing access_token in login request"))?;
-            let access_token = private_key
-                .decrypt_string(&access_token)
-                .context("failed to decrypt access token")?;
-            platform.write_credentials(&zed_url, &user_id, access_token.as_bytes());
-            log::info!("successfully signed in. user_id: {}", user_id);
-
-            Ok((user_id.to_string(), access_token))
-        })
-        .detach();
+        Ok((user_id.to_string(), access_token))
+    })
 }
 
 fn quit(_: &(), cx: &mut MutableAppContext) {

zed/src/menus.rs 🔗

@@ -15,9 +15,9 @@ pub fn menus(state: AppState) -> Vec<Menu<'static>> {
                 },
                 MenuItem::Separator,
                 MenuItem::Action {
-                    name: "Log In",
+                    name: "Share",
                     keystroke: None,
-                    action: "app:authenticate",
+                    action: "app:share_worktree",
                     arg: None,
                 },
                 MenuItem::Action {

zed/src/util.rs 🔗

@@ -106,3 +106,33 @@ mod tests {
         assert_eq!(vec, &[1000, 101, 21, 19, 17, 13, 9, 8]);
     }
 }
+
+// Allow surf Results to accept context like other Results do when
+// using anyhow.
+pub trait SurfResultExt {
+    fn context<C>(self, cx: C) -> Self
+    where
+        C: std::fmt::Display + Send + Sync + 'static;
+
+    fn with_context<C, F>(self, f: F) -> Self
+    where
+        C: std::fmt::Display + Send + Sync + 'static,
+        F: FnOnce() -> C;
+}
+
+impl<T> SurfResultExt for surf::Result<T> {
+    fn context<C>(self, cx: C) -> Self
+    where
+        C: std::fmt::Display + Send + Sync + 'static,
+    {
+        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(cx)))
+    }
+
+    fn with_context<C, F>(self, f: F) -> Self
+    where
+        C: std::fmt::Display + Send + Sync + 'static,
+        F: FnOnce() -> C,
+    {
+        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(f())))
+    }
+}