mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-28 21:32:39 +00:00
Merge pull request #859 from zed-industries/cli
Add a zed command-line tool
This commit is contained in:
commit
1da515010b
17 changed files with 818 additions and 204 deletions
364
Cargo.lock
generated
364
Cargo.lock
generated
|
@ -135,7 +135,7 @@ version = "0.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -309,7 +309,7 @@ dependencies = [
|
|||
"polling",
|
||||
"vec-arena",
|
||||
"waker-fn",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -364,7 +364,7 @@ dependencies = [
|
|||
"futures-lite",
|
||||
"once_cell",
|
||||
"signal-hook",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -458,7 +458,7 @@ dependencies = [
|
|||
"async-io",
|
||||
"async-lock",
|
||||
"async-process",
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
|
@ -550,7 +550,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
|||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -909,7 +909,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"serde",
|
||||
"time 0.1.44",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -964,9 +964,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.0.0-beta.2"
|
||||
version = "3.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142"
|
||||
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
|
@ -976,24 +976,36 @@ dependencies = [
|
|||
"os_str_bytes",
|
||||
"strsim 0.10.0",
|
||||
"termcolor",
|
||||
"textwrap 0.12.1",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
"textwrap 0.15.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.0.0-beta.2"
|
||||
version = "3.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1"
|
||||
checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.4.0",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 3.1.8",
|
||||
"core-foundation",
|
||||
"core-services",
|
||||
"dirs 3.0.1",
|
||||
"ipc-channel",
|
||||
"plist",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "client"
|
||||
version = "0.1.0"
|
||||
|
@ -1087,7 +1099,7 @@ dependencies = [
|
|||
"async-trait",
|
||||
"async-tungstenite",
|
||||
"base64 0.13.0",
|
||||
"clap 3.0.0-beta.2",
|
||||
"clap 3.1.8",
|
||||
"client",
|
||||
"collections",
|
||||
"comrak",
|
||||
|
@ -1272,6 +1284,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-services"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b344b958cae90858bf6086f49599ecc5ec8698eacad0ea155509ba11fab347"
|
||||
dependencies = [
|
||||
"core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-text"
|
||||
version = "19.2.0"
|
||||
|
@ -1326,6 +1347,16 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.7.2",
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.0"
|
||||
|
@ -1333,7 +1364,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1344,7 +1375,7 @@ checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
|||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1354,7 +1385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d60ab4a8dba064f2fbb5aa270c28da5cf4bbd0e72dae1140a6b0353a779dbe00"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
"lazy_static",
|
||||
"loom",
|
||||
"memoffset",
|
||||
|
@ -1368,7 +1399,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "0f6cb3c7f5b8e51bc3ebb73a2327ad4abdbd119dc13223f14f961d2f38486756"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"cfg-if 0.1.10",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1472,7 +1514,7 @@ dependencies = [
|
|||
"openssl-sys",
|
||||
"schannel",
|
||||
"socket2 0.4.0",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1488,7 +1530,7 @@ dependencies = [
|
|||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1634,7 +1676,7 @@ checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1645,7 +1687,7 @@ checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1668,7 +1710,7 @@ checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b"
|
|||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
"wio",
|
||||
]
|
||||
|
||||
|
@ -1865,9 +1907,9 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
|||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.4.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3"
|
||||
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
@ -1985,7 +2027,7 @@ dependencies = [
|
|||
"pathfinder_simd",
|
||||
"servo-fontconfig",
|
||||
"walkdir",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2070,6 +2112,22 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fuchsia-zircon-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "1.1.0"
|
||||
|
@ -2201,7 +2259,7 @@ dependencies = [
|
|||
"libc",
|
||||
"log",
|
||||
"rustc_version",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2449,6 +2507,12 @@ dependencies = [
|
|||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
|
@ -2530,7 +2594,7 @@ checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
|
|||
dependencies = [
|
||||
"bytes 1.0.1",
|
||||
"fnv",
|
||||
"itoa",
|
||||
"itoa 0.4.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2608,7 +2672,7 @@ version = "0.4.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
"globset",
|
||||
"lazy_static",
|
||||
"log",
|
||||
|
@ -2673,6 +2737,34 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipc-channel"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cb1d9211085f0ea6f1379d944b93c4d07e8207aa3bcf49f37eda12b85081887"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"crossbeam-channel 0.4.4",
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"mio",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"tempfile",
|
||||
"uuid",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isahc"
|
||||
version = "0.9.14"
|
||||
|
@ -2680,7 +2772,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a"
|
||||
dependencies = [
|
||||
"bytes 0.5.6",
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
"curl",
|
||||
"curl-sys",
|
||||
"flume",
|
||||
|
@ -2711,6 +2803,12 @@ version = "0.4.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.24"
|
||||
|
@ -2797,6 +2895,16 @@ dependencies = [
|
|||
"sha2 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kurbo"
|
||||
version = "0.8.1"
|
||||
|
@ -2893,7 +3001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2924,6 +3032,15 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "line-wrap"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
|
||||
dependencies = [
|
||||
"safemem",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lipsum"
|
||||
version = "0.8.0"
|
||||
|
@ -3031,6 +3148,12 @@ version = "0.1.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.9.1"
|
||||
|
@ -3124,6 +3247,37 @@ dependencies = [
|
|||
"autocfg 1.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"iovec",
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"net2",
|
||||
"winapi 0.2.8",
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.8.3"
|
||||
|
@ -3140,6 +3294,17 @@ dependencies = [
|
|||
"socket2 0.3.19",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.2"
|
||||
|
@ -3361,9 +3526,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "2.4.0"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85"
|
||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "outline"
|
||||
|
@ -3421,7 +3589,7 @@ dependencies = [
|
|||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3625,6 +3793,20 @@ version = "0.3.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"indexmap",
|
||||
"line-wrap",
|
||||
"serde",
|
||||
"time 0.3.7",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.16.8"
|
||||
|
@ -3647,7 +3829,7 @@ dependencies = [
|
|||
"libc",
|
||||
"log",
|
||||
"wepoll-sys",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3727,9 +3909,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
@ -3823,7 +4005,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603"
|
||||
dependencies = [
|
||||
"bytes 1.0.1",
|
||||
"heck",
|
||||
"heck 0.3.3",
|
||||
"itertools",
|
||||
"log",
|
||||
"multimap",
|
||||
|
@ -3888,7 +4070,7 @@ dependencies = [
|
|||
"libc",
|
||||
"rand_core 0.3.1",
|
||||
"rdrand",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4005,9 +4187,9 @@ version = "1.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-channel 0.5.0",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
]
|
||||
|
@ -4069,7 +4251,7 @@ version = "0.5.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4109,7 +4291,7 @@ dependencies = [
|
|||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4286,6 +4468,12 @@ dependencies = [
|
|||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "safemem"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
|
||||
|
||||
[[package]]
|
||||
name = "salsa20"
|
||||
version = "0.8.0"
|
||||
|
@ -4311,7 +4499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4488,7 +4676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"itoa 0.4.7",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
@ -4532,7 +4720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"itoa 0.4.7",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
@ -4791,7 +4979,7 @@ checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
|
|||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4801,7 +4989,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4875,9 +5063,9 @@ dependencies = [
|
|||
"bytes 0.5.6",
|
||||
"chrono",
|
||||
"crc",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-channel 0.5.0",
|
||||
"crossbeam-queue",
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
"either",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
@ -4885,7 +5073,7 @@ dependencies = [
|
|||
"hashlink 0.6.0",
|
||||
"hex",
|
||||
"hmac 0.10.1",
|
||||
"itoa",
|
||||
"itoa 0.4.7",
|
||||
"libc",
|
||||
"log",
|
||||
"md-5",
|
||||
|
@ -4923,9 +5111,9 @@ dependencies = [
|
|||
"byteorder",
|
||||
"bytes 1.0.1",
|
||||
"crc",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-channel 0.5.0",
|
||||
"crossbeam-queue",
|
||||
"crossbeam-utils",
|
||||
"crossbeam-utils 0.8.2",
|
||||
"dirs 3.0.1",
|
||||
"either",
|
||||
"futures-channel",
|
||||
|
@ -4934,7 +5122,7 @@ dependencies = [
|
|||
"hashlink 0.7.0",
|
||||
"hex",
|
||||
"hmac 0.10.1",
|
||||
"itoa",
|
||||
"itoa 0.4.7",
|
||||
"libc",
|
||||
"log",
|
||||
"md-5",
|
||||
|
@ -4971,7 +5159,7 @@ dependencies = [
|
|||
"dotenv",
|
||||
"either",
|
||||
"futures",
|
||||
"heck",
|
||||
"heck 0.3.3",
|
||||
"lazy_static",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -4992,7 +5180,7 @@ dependencies = [
|
|||
"dotenv",
|
||||
"either",
|
||||
"futures",
|
||||
"heck",
|
||||
"heck 0.3.3",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -5191,9 +5379,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.67"
|
||||
version = "1.0.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702"
|
||||
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -5230,16 +5418,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.2.0"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"rand 0.8.3",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5283,12 +5471,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.12.1"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
|
||||
[[package]]
|
||||
name = "theme"
|
||||
|
@ -5410,7 +5595,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5425,7 +5610,7 @@ dependencies = [
|
|||
"stdweb",
|
||||
"time-macros",
|
||||
"version_check",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5434,6 +5619,7 @@ version = "0.3.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d"
|
||||
dependencies = [
|
||||
"itoa 1.0.1",
|
||||
"libc",
|
||||
"num_threads",
|
||||
]
|
||||
|
@ -5846,6 +6032,9 @@ name = "uuid"
|
|||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
|
@ -5916,7 +6105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
|
@ -6073,6 +6262,12 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -6083,6 +6278,12 @@ dependencies = [
|
|||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -6095,7 +6296,7 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6110,7 +6311,7 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6136,6 +6337,16 @@ dependencies = [
|
|||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.2.0"
|
||||
|
@ -6148,6 +6359,12 @@ version = "2.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||
|
||||
[[package]]
|
||||
name = "xmlparser"
|
||||
version = "0.13.3"
|
||||
|
@ -6171,6 +6388,7 @@ dependencies = [
|
|||
"async-trait",
|
||||
"breadcrumbs",
|
||||
"chat_panel",
|
||||
"cli",
|
||||
"client",
|
||||
"clock",
|
||||
"collections",
|
||||
|
|
24
crates/cli/Cargo.toml
Normal file
24
crates/cli/Cargo.toml
Normal file
|
@ -0,0 +1,24 @@
|
|||
[package]
|
||||
name = "cli"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
path = "src/cli.rs"
|
||||
doctest = false
|
||||
|
||||
[[bin]]
|
||||
name = "cli"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
clap = { version = "3.1", features = ["derive"] }
|
||||
dirs = "3.0"
|
||||
ipc-channel = "0.16"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation = "0.9"
|
||||
core-services = "0.2"
|
||||
plist = "1.3"
|
22
crates/cli/src/cli.rs
Normal file
22
crates/cli/src/cli.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
pub use ipc_channel::ipc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct IpcHandshake {
|
||||
pub requests: ipc::IpcSender<CliRequest>,
|
||||
pub responses: ipc::IpcReceiver<CliResponse>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum CliRequest {
|
||||
Open { paths: Vec<PathBuf>, wait: bool },
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum CliResponse {
|
||||
Ping,
|
||||
Stdout { message: String },
|
||||
Stderr { message: String },
|
||||
Exit { status: i32 },
|
||||
}
|
124
crates/cli/src/main.rs
Normal file
124
crates/cli/src/main.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use clap::Parser;
|
||||
use cli::{CliRequest, CliResponse, IpcHandshake};
|
||||
use core_foundation::{
|
||||
array::{CFArray, CFIndex},
|
||||
string::kCFStringEncodingUTF8,
|
||||
url::{CFURLCreateWithBytes, CFURL},
|
||||
};
|
||||
use core_services::{kLSLaunchDefaults, LSLaunchURLSpec, LSOpenFromURLSpec, TCFType};
|
||||
use ipc_channel::ipc::{IpcOneShotServer, IpcReceiver, IpcSender};
|
||||
use serde::Deserialize;
|
||||
use std::{ffi::OsStr, fs, path::PathBuf, ptr};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(name = "zed", global_setting(clap::AppSettings::NoAutoVersion))]
|
||||
struct Args {
|
||||
/// Wait for all of the given paths to be closed before exiting.
|
||||
#[clap(short, long)]
|
||||
wait: bool,
|
||||
/// A sequence of space-separated paths that you want to open.
|
||||
#[clap()]
|
||||
paths: Vec<PathBuf>,
|
||||
/// Print Zed's version and the app path.
|
||||
#[clap(short, long)]
|
||||
version: bool,
|
||||
/// Custom Zed.app path
|
||||
#[clap(short, long)]
|
||||
bundle_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct InfoPlist {
|
||||
#[serde(rename = "CFBundleShortVersionString")]
|
||||
bundle_short_version_string: String,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
let bundle_path = if let Some(bundle_path) = args.bundle_path {
|
||||
bundle_path.canonicalize()?
|
||||
} else {
|
||||
locate_bundle()?
|
||||
};
|
||||
|
||||
if args.version {
|
||||
let plist_path = bundle_path.join("Contents/Info.plist");
|
||||
let plist = plist::from_file::<_, InfoPlist>(plist_path)?;
|
||||
println!(
|
||||
"Zed {} – {}",
|
||||
plist.bundle_short_version_string,
|
||||
bundle_path.to_string_lossy()
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (tx, rx) = launch_app(bundle_path)?;
|
||||
|
||||
tx.send(CliRequest::Open {
|
||||
paths: args
|
||||
.paths
|
||||
.into_iter()
|
||||
.map(|path| fs::canonicalize(path).map_err(|error| anyhow!(error)))
|
||||
.collect::<Result<Vec<PathBuf>>>()?,
|
||||
wait: args.wait,
|
||||
})?;
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
fn locate_bundle() -> Result<PathBuf> {
|
||||
let cli_path = std::env::current_exe()?.canonicalize()?;
|
||||
let mut app_path = cli_path.clone();
|
||||
while app_path.extension() != Some(OsStr::new("app")) {
|
||||
if !app_path.pop() {
|
||||
return Err(anyhow!("cannot find app bundle containing {:?}", cli_path));
|
||||
}
|
||||
}
|
||||
Ok(app_path)
|
||||
}
|
||||
|
||||
fn launch_app(app_path: PathBuf) -> Result<(IpcSender<CliRequest>, IpcReceiver<CliResponse>)> {
|
||||
let (server, server_name) = IpcOneShotServer::<IpcHandshake>::new()?;
|
||||
let url = format!("zed-cli://{server_name}");
|
||||
|
||||
let status = unsafe {
|
||||
let app_url =
|
||||
CFURL::from_path(&app_path, true).ok_or_else(|| anyhow!("invalid app path"))?;
|
||||
let url_to_open = CFURL::wrap_under_create_rule(CFURLCreateWithBytes(
|
||||
ptr::null(),
|
||||
url.as_ptr(),
|
||||
url.len() as CFIndex,
|
||||
kCFStringEncodingUTF8,
|
||||
ptr::null(),
|
||||
));
|
||||
let urls_to_open = CFArray::from_copyable(&[url_to_open.as_concrete_TypeRef()]);
|
||||
LSOpenFromURLSpec(
|
||||
&LSLaunchURLSpec {
|
||||
appURL: app_url.as_concrete_TypeRef(),
|
||||
itemURLs: urls_to_open.as_concrete_TypeRef(),
|
||||
passThruParams: ptr::null(),
|
||||
launchFlags: kLSLaunchDefaults,
|
||||
asyncRefCon: ptr::null_mut(),
|
||||
},
|
||||
ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
|
||||
if status == 0 {
|
||||
let (_, handshake) = server.accept()?;
|
||||
Ok((handshake.requests, handshake.responses))
|
||||
} else {
|
||||
Err(anyhow!("cannot start {:?}", app_path))
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
|
|||
async-trait = "0.1.50"
|
||||
async-tungstenite = "0.16"
|
||||
base64 = "0.13"
|
||||
clap = "=3.0.0-beta.2"
|
||||
clap = "3.1"
|
||||
comrak = "0.10"
|
||||
either = "1.6"
|
||||
envy = "0.4.2"
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use client::{Contact, UserStore};
|
||||
use gpui::{
|
||||
elements::*,
|
||||
|
@ -8,8 +6,9 @@ use gpui::{
|
|||
Element, ElementBox, Entity, LayoutContext, ModelHandle, RenderContext, Subscription, View,
|
||||
ViewContext,
|
||||
};
|
||||
use workspace::{AppState, JoinProject, JoinProjectParams};
|
||||
use settings::Settings;
|
||||
use std::sync::Arc;
|
||||
use workspace::{AppState, JoinProject};
|
||||
|
||||
pub struct ContactsPanel {
|
||||
contacts: ListState,
|
||||
|
@ -207,10 +206,10 @@ impl ContactsPanel {
|
|||
})
|
||||
.on_click(move |cx| {
|
||||
if !is_host && !is_guest {
|
||||
cx.dispatch_global_action(JoinProject(JoinProjectParams {
|
||||
cx.dispatch_global_action(JoinProject {
|
||||
project_id,
|
||||
app_state: app_state.clone(),
|
||||
}));
|
||||
});
|
||||
}
|
||||
})
|
||||
.flex(1., true)
|
||||
|
|
|
@ -248,7 +248,7 @@ impl App {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn on_quit<F>(self, mut callback: F) -> Self
|
||||
pub fn on_quit<F>(&mut self, mut callback: F) -> &mut Self
|
||||
where
|
||||
F: 'static + FnMut(&mut MutableAppContext),
|
||||
{
|
||||
|
@ -260,7 +260,7 @@ impl App {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn on_event<F>(self, mut callback: F) -> Self
|
||||
pub fn on_event<F>(&mut self, mut callback: F) -> &mut Self
|
||||
where
|
||||
F: 'static + FnMut(Event, &mut MutableAppContext) -> bool,
|
||||
{
|
||||
|
@ -274,15 +274,15 @@ impl App {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn on_open_files<F>(self, mut callback: F) -> Self
|
||||
pub fn on_open_urls<F>(&mut self, mut callback: F) -> &mut Self
|
||||
where
|
||||
F: 'static + FnMut(Vec<PathBuf>, &mut MutableAppContext),
|
||||
F: 'static + FnMut(Vec<String>, &mut MutableAppContext),
|
||||
{
|
||||
let cx = self.0.clone();
|
||||
self.0
|
||||
.borrow_mut()
|
||||
.foreground_platform
|
||||
.on_open_files(Box::new(move |paths| {
|
||||
.on_open_urls(Box::new(move |paths| {
|
||||
callback(paths, &mut *cx.borrow_mut())
|
||||
}));
|
||||
self
|
||||
|
@ -719,7 +719,7 @@ type GlobalSubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext
|
|||
type ObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
|
||||
type FocusObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
|
||||
type GlobalObservationCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
|
||||
type ReleaseObservationCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
|
||||
type ReleaseObservationCallback = Box<dyn FnOnce(&dyn Any, &mut MutableAppContext)>;
|
||||
type DeserializeActionCallback = fn(json: &str) -> anyhow::Result<Box<dyn Action>>;
|
||||
|
||||
pub struct MutableAppContext {
|
||||
|
@ -1245,12 +1245,12 @@ impl MutableAppContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn observe_release<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
|
||||
pub fn observe_release<E, H, F>(&mut self, handle: &H, callback: F) -> Subscription
|
||||
where
|
||||
E: Entity,
|
||||
E::Event: 'static,
|
||||
H: Handle<E>,
|
||||
F: 'static + FnMut(&E, &mut Self),
|
||||
F: 'static + FnOnce(&E, &mut Self),
|
||||
{
|
||||
let id = post_inc(&mut self.next_subscription_id);
|
||||
self.release_observations
|
||||
|
@ -2197,7 +2197,7 @@ impl MutableAppContext {
|
|||
fn handle_entity_release_effect(&mut self, entity_id: usize, entity: &dyn Any) {
|
||||
let callbacks = self.release_observations.lock().remove(&entity_id);
|
||||
if let Some(callbacks) = callbacks {
|
||||
for (_, mut callback) in callbacks {
|
||||
for (_, callback) in callbacks {
|
||||
callback(entity, self);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,8 +54,7 @@ pub trait Platform: Send + Sync {
|
|||
fn set_cursor_style(&self, style: CursorStyle);
|
||||
|
||||
fn local_timezone(&self) -> UtcOffset;
|
||||
|
||||
fn path_for_resource(&self, name: Option<&str>, extension: Option<&str>) -> Result<PathBuf>;
|
||||
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
|
||||
}
|
||||
|
||||
pub(crate) trait ForegroundPlatform {
|
||||
|
@ -63,7 +62,7 @@ pub(crate) trait ForegroundPlatform {
|
|||
fn on_resign_active(&self, callback: Box<dyn FnMut()>);
|
||||
fn on_quit(&self, callback: Box<dyn FnMut()>);
|
||||
fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>);
|
||||
fn on_open_files(&self, callback: Box<dyn FnMut(Vec<PathBuf>)>);
|
||||
fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);
|
||||
fn run(&self, on_finish_launching: Box<dyn FnOnce() -> ()>);
|
||||
|
||||
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>);
|
||||
|
|
|
@ -14,9 +14,7 @@ use cocoa::{
|
|||
NSPasteboardTypeString, NSSavePanel, NSWindow,
|
||||
},
|
||||
base::{id, nil, selector, YES},
|
||||
foundation::{
|
||||
NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSString, NSUInteger, NSURL,
|
||||
},
|
||||
foundation::{NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSString, NSURL},
|
||||
};
|
||||
use core_foundation::{
|
||||
base::{CFType, CFTypeRef, OSStatus, TCFType as _},
|
||||
|
@ -38,8 +36,8 @@ use ptr::null_mut;
|
|||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
convert::TryInto,
|
||||
ffi::{c_void, CStr},
|
||||
os::raw::c_char,
|
||||
ffi::{c_void, CStr, OsStr},
|
||||
os::{raw::c_char, unix::ffi::OsStrExt},
|
||||
path::{Path, PathBuf},
|
||||
ptr,
|
||||
rc::Rc,
|
||||
|
@ -48,9 +46,6 @@ use std::{
|
|||
};
|
||||
use time::UtcOffset;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const NSUTF8StringEncoding: NSUInteger = 4;
|
||||
|
||||
const MAC_PLATFORM_IVAR: &'static str = "platform";
|
||||
static mut APP_CLASS: *const Class = ptr::null();
|
||||
static mut APP_DELEGATE_CLASS: *const Class = ptr::null();
|
||||
|
@ -91,8 +86,8 @@ unsafe fn build_classes() {
|
|||
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(application:openFiles:),
|
||||
open_files as extern "C" fn(&mut Object, Sel, id, id),
|
||||
sel!(application:openURLs:),
|
||||
open_urls as extern "C" fn(&mut Object, Sel, id, id),
|
||||
);
|
||||
decl.register()
|
||||
}
|
||||
|
@ -108,7 +103,7 @@ pub struct MacForegroundPlatformState {
|
|||
quit: Option<Box<dyn FnMut()>>,
|
||||
event: Option<Box<dyn FnMut(crate::Event) -> bool>>,
|
||||
menu_command: Option<Box<dyn FnMut(&dyn Action)>>,
|
||||
open_files: Option<Box<dyn FnMut(Vec<PathBuf>)>>,
|
||||
open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
|
||||
finish_launching: Option<Box<dyn FnOnce() -> ()>>,
|
||||
menu_actions: Vec<Box<dyn Action>>,
|
||||
}
|
||||
|
@ -210,8 +205,8 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
|
|||
self.0.borrow_mut().event = Some(callback);
|
||||
}
|
||||
|
||||
fn on_open_files(&self, callback: Box<dyn FnMut(Vec<PathBuf>)>) {
|
||||
self.0.borrow_mut().open_files = Some(callback);
|
||||
fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>) {
|
||||
self.0.borrow_mut().open_urls = Some(callback);
|
||||
}
|
||||
|
||||
fn run(&self, on_finish_launching: Box<dyn FnOnce() -> ()>) {
|
||||
|
@ -265,10 +260,9 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
|
|||
for i in 0..urls.count() {
|
||||
let url = urls.objectAtIndex(i);
|
||||
if url.isFileURL() == YES {
|
||||
let path = std::ffi::CStr::from_ptr(url.path().UTF8String())
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
result.push(PathBuf::from(path));
|
||||
if let Ok(path) = ns_url_to_path(url) {
|
||||
result.push(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(result)
|
||||
|
@ -296,19 +290,13 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
|
|||
let (done_tx, done_rx) = oneshot::channel();
|
||||
let done_tx = Cell::new(Some(done_tx));
|
||||
let block = ConcreteBlock::new(move |response: NSModalResponse| {
|
||||
let result = if response == NSModalResponse::NSModalResponseOk {
|
||||
let mut result = None;
|
||||
if response == NSModalResponse::NSModalResponseOk {
|
||||
let url = panel.URL();
|
||||
if url.isFileURL() == YES {
|
||||
let path = std::ffi::CStr::from_ptr(url.path().UTF8String())
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
Some(PathBuf::from(path))
|
||||
} else {
|
||||
None
|
||||
result = ns_url_to_path(panel.URL()).ok()
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(mut done_tx) = done_tx.take() {
|
||||
let _ = postage::sink::Sink::try_send(&mut done_tx, result);
|
||||
|
@ -603,22 +591,18 @@ impl platform::Platform for MacPlatform {
|
|||
}
|
||||
}
|
||||
|
||||
fn path_for_resource(&self, name: Option<&str>, extension: Option<&str>) -> Result<PathBuf> {
|
||||
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
||||
unsafe {
|
||||
let bundle: id = NSBundle::mainBundle();
|
||||
if bundle.is_null() {
|
||||
Err(anyhow!("app is not running inside a bundle"))
|
||||
} else {
|
||||
let name = name.map_or(nil, |name| ns_string(name));
|
||||
let extension = extension.map_or(nil, |extension| ns_string(extension));
|
||||
let path: id = msg_send![bundle, pathForResource: name ofType: extension];
|
||||
if path.is_null() {
|
||||
Err(anyhow!("resource could not be found"))
|
||||
let name = ns_string(name);
|
||||
let url: id = msg_send![bundle, URLForAuxiliaryExecutable: name];
|
||||
if url.is_null() {
|
||||
Err(anyhow!("resource not found"))
|
||||
} else {
|
||||
let len = msg_send![path, lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
|
||||
let bytes = path.UTF8String() as *const u8;
|
||||
let path = str::from_utf8(slice::from_raw_parts(bytes, len)).unwrap();
|
||||
Ok(PathBuf::from(path))
|
||||
ns_url_to_path(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -680,14 +664,14 @@ extern "C" fn will_terminate(this: &mut Object, _: Sel, _: id) {
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" fn open_files(this: &mut Object, _: Sel, _: id, paths: id) {
|
||||
let paths = unsafe {
|
||||
(0..paths.count())
|
||||
extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) {
|
||||
let urls = unsafe {
|
||||
(0..urls.count())
|
||||
.into_iter()
|
||||
.filter_map(|i| {
|
||||
let path = paths.objectAtIndex(i);
|
||||
match CStr::from_ptr(path.UTF8String() as *mut c_char).to_str() {
|
||||
Ok(string) => Some(PathBuf::from(string)),
|
||||
let path = urls.objectAtIndex(i);
|
||||
match CStr::from_ptr(path.absoluteString().UTF8String() as *mut c_char).to_str() {
|
||||
Ok(string) => Some(string.to_string()),
|
||||
Err(err) => {
|
||||
log::error!("error converting path to string: {}", err);
|
||||
None
|
||||
|
@ -697,8 +681,8 @@ extern "C" fn open_files(this: &mut Object, _: Sel, _: id, paths: id) {
|
|||
.collect::<Vec<_>>()
|
||||
};
|
||||
let platform = unsafe { get_foreground_platform(this) };
|
||||
if let Some(callback) = platform.0.borrow_mut().open_files.as_mut() {
|
||||
callback(paths);
|
||||
if let Some(callback) = platform.0.borrow_mut().open_urls.as_mut() {
|
||||
callback(urls);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -721,6 +705,20 @@ unsafe fn ns_string(string: &str) -> id {
|
|||
NSString::alloc(nil).init_str(string).autorelease()
|
||||
}
|
||||
|
||||
unsafe fn ns_url_to_path(url: id) -> Result<PathBuf> {
|
||||
let path: *mut c_char = msg_send![url, fileSystemRepresentation];
|
||||
if path.is_null() {
|
||||
Err(anyhow!(
|
||||
"url is not a file path: {}",
|
||||
CStr::from_ptr(url.absoluteString().UTF8String()).to_string_lossy()
|
||||
))
|
||||
} else {
|
||||
Ok(PathBuf::from(OsStr::from_bytes(
|
||||
CStr::from_ptr(path).to_bytes(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
mod security {
|
||||
#![allow(non_upper_case_globals)]
|
||||
use super::*;
|
||||
|
|
|
@ -66,7 +66,7 @@ impl super::ForegroundPlatform for ForegroundPlatform {
|
|||
|
||||
fn on_event(&self, _: Box<dyn FnMut(crate::Event) -> bool>) {}
|
||||
|
||||
fn on_open_files(&self, _: Box<dyn FnMut(Vec<std::path::PathBuf>)>) {}
|
||||
fn on_open_urls(&self, _: Box<dyn FnMut(Vec<String>)>) {}
|
||||
|
||||
fn run(&self, _on_finish_launching: Box<dyn FnOnce() -> ()>) {
|
||||
unimplemented!()
|
||||
|
@ -161,7 +161,7 @@ impl super::Platform for Platform {
|
|||
UtcOffset::UTC
|
||||
}
|
||||
|
||||
fn path_for_resource(&self, _name: Option<&str>, _extension: Option<&str>) -> Result<PathBuf> {
|
||||
fn path_for_auxiliary_executable(&self, _name: &str) -> Result<PathBuf> {
|
||||
Err(anyhow!("app not running inside a bundle"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ pub fn new_journal_entry(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
|
|||
cx.spawn(|mut cx| {
|
||||
async move {
|
||||
let (journal_dir, entry_path) = create_entry.await?;
|
||||
let workspace = cx
|
||||
let (workspace, _) = cx
|
||||
.update(|cx| workspace::open_paths(&[journal_dir], &app_state, cx))
|
||||
.await;
|
||||
|
||||
|
|
|
@ -97,7 +97,10 @@ pub struct OpenPaths {
|
|||
pub struct ToggleFollow(pub PeerId);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct JoinProject(pub JoinProjectParams);
|
||||
pub struct JoinProject {
|
||||
pub project_id: u64,
|
||||
pub app_state: Arc<AppState>,
|
||||
}
|
||||
|
||||
impl_internal_actions!(
|
||||
workspace,
|
||||
|
@ -115,7 +118,7 @@ pub fn init(client: &Arc<Client>, cx: &mut MutableAppContext) {
|
|||
open_new(&action.0, cx)
|
||||
});
|
||||
cx.add_global_action(move |action: &JoinProject, cx: &mut MutableAppContext| {
|
||||
join_project(action.0.project_id, &action.0.app_state, cx).detach();
|
||||
join_project(action.project_id, &action.app_state, cx).detach();
|
||||
});
|
||||
|
||||
cx.add_action(Workspace::toggle_share);
|
||||
|
@ -187,12 +190,6 @@ pub struct AppState {
|
|||
) -> Workspace,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct JoinProjectParams {
|
||||
pub project_id: u64,
|
||||
pub app_state: Arc<AppState>,
|
||||
}
|
||||
|
||||
pub trait Item: View {
|
||||
fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
|
||||
fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool {
|
||||
|
@ -379,6 +376,11 @@ pub trait ItemHandle: 'static + fmt::Debug {
|
|||
-> Task<Result<()>>;
|
||||
fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option<AnyViewHandle>;
|
||||
fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>>;
|
||||
fn on_release(
|
||||
&self,
|
||||
cx: &mut MutableAppContext,
|
||||
callback: Box<dyn FnOnce(&mut MutableAppContext)>,
|
||||
) -> gpui::Subscription;
|
||||
}
|
||||
|
||||
pub trait WeakItemHandle {
|
||||
|
@ -414,6 +416,12 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
|
|||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn set_nav_history(&self, nav_history: Rc<RefCell<NavHistory>>, cx: &mut MutableAppContext) {
|
||||
self.update(cx, |item, cx| {
|
||||
item.set_nav_history(ItemNavHistory::new(nav_history, &cx.handle()), cx);
|
||||
})
|
||||
}
|
||||
|
||||
fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option<Box<dyn ItemHandle>> {
|
||||
self.update(cx, |item, cx| {
|
||||
cx.add_option_view(|cx| item.clone_on_split(cx))
|
||||
|
@ -421,12 +429,6 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
|
|||
.map(|handle| Box::new(handle) as Box<dyn ItemHandle>)
|
||||
}
|
||||
|
||||
fn set_nav_history(&self, nav_history: Rc<RefCell<NavHistory>>, cx: &mut MutableAppContext) {
|
||||
self.update(cx, |item, cx| {
|
||||
item.set_nav_history(ItemNavHistory::new(nav_history, &cx.handle()), cx);
|
||||
})
|
||||
}
|
||||
|
||||
fn added_to_pane(
|
||||
&self,
|
||||
workspace: &mut Workspace,
|
||||
|
@ -515,6 +517,30 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
|
|||
self.update(cx, |this, cx| this.navigate(data, cx))
|
||||
}
|
||||
|
||||
fn id(&self) -> usize {
|
||||
self.id()
|
||||
}
|
||||
|
||||
fn to_any(&self) -> AnyViewHandle {
|
||||
self.into()
|
||||
}
|
||||
|
||||
fn is_dirty(&self, cx: &AppContext) -> bool {
|
||||
self.read(cx).is_dirty(cx)
|
||||
}
|
||||
|
||||
fn has_conflict(&self, cx: &AppContext) -> bool {
|
||||
self.read(cx).has_conflict(cx)
|
||||
}
|
||||
|
||||
fn can_save(&self, cx: &AppContext) -> bool {
|
||||
self.read(cx).can_save(cx)
|
||||
}
|
||||
|
||||
fn can_save_as(&self, cx: &AppContext) -> bool {
|
||||
self.read(cx).can_save_as(cx)
|
||||
}
|
||||
|
||||
fn save(&self, project: ModelHandle<Project>, cx: &mut MutableAppContext) -> Task<Result<()>> {
|
||||
self.update(cx, |item, cx| item.save(project, cx))
|
||||
}
|
||||
|
@ -536,30 +562,6 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
|
|||
self.update(cx, |item, cx| item.reload(project, cx))
|
||||
}
|
||||
|
||||
fn is_dirty(&self, cx: &AppContext) -> bool {
|
||||
self.read(cx).is_dirty(cx)
|
||||
}
|
||||
|
||||
fn has_conflict(&self, cx: &AppContext) -> bool {
|
||||
self.read(cx).has_conflict(cx)
|
||||
}
|
||||
|
||||
fn id(&self) -> usize {
|
||||
self.id()
|
||||
}
|
||||
|
||||
fn to_any(&self) -> AnyViewHandle {
|
||||
self.into()
|
||||
}
|
||||
|
||||
fn can_save(&self, cx: &AppContext) -> bool {
|
||||
self.read(cx).can_save(cx)
|
||||
}
|
||||
|
||||
fn can_save_as(&self, cx: &AppContext) -> bool {
|
||||
self.read(cx).can_save_as(cx)
|
||||
}
|
||||
|
||||
fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option<AnyViewHandle> {
|
||||
self.read(cx).act_as_type(type_id, self, cx)
|
||||
}
|
||||
|
@ -573,6 +575,14 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn on_release(
|
||||
&self,
|
||||
cx: &mut MutableAppContext,
|
||||
callback: Box<dyn FnOnce(&mut MutableAppContext)>,
|
||||
) -> gpui::Subscription {
|
||||
cx.observe_release(self, move |_, cx| callback(cx))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<AnyViewHandle> for Box<dyn ItemHandle> {
|
||||
|
@ -2105,7 +2115,10 @@ pub fn open_paths(
|
|||
abs_paths: &[PathBuf],
|
||||
app_state: &Arc<AppState>,
|
||||
cx: &mut MutableAppContext,
|
||||
) -> Task<ViewHandle<Workspace>> {
|
||||
) -> Task<(
|
||||
ViewHandle<Workspace>,
|
||||
Vec<Option<Result<Box<dyn ItemHandle>, Arc<anyhow::Error>>>>,
|
||||
)> {
|
||||
log::info!("open paths {:?}", abs_paths);
|
||||
|
||||
// Open paths in existing workspace if possible
|
||||
|
@ -2142,8 +2155,8 @@ pub fn open_paths(
|
|||
|
||||
let task = workspace.update(cx, |workspace, cx| workspace.open_paths(abs_paths, cx));
|
||||
cx.spawn(|_| async move {
|
||||
task.await;
|
||||
workspace
|
||||
let items = task.await;
|
||||
(workspace, items)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ test-support = [
|
|||
assets = { path = "../assets" }
|
||||
breadcrumbs = { path = "../breadcrumbs" }
|
||||
chat_panel = { path = "../chat_panel" }
|
||||
cli = { path = "../cli" }
|
||||
collections = { path = "../collections" }
|
||||
command_palette = { path = "../command_palette" }
|
||||
client = { path = "../client" }
|
||||
|
|
|
@ -3,16 +3,23 @@
|
|||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use assets::Assets;
|
||||
use cli::{
|
||||
ipc::{self, IpcSender},
|
||||
CliRequest, CliResponse, IpcHandshake,
|
||||
};
|
||||
use client::{self, http, ChannelList, UserStore};
|
||||
use fs::OpenOptions;
|
||||
use futures::{channel::oneshot, StreamExt};
|
||||
use gpui::{App, AssetSource, Task};
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
FutureExt, SinkExt, StreamExt,
|
||||
};
|
||||
use gpui::{App, AssetSource, AsyncAppContext, Task};
|
||||
use log::LevelFilter;
|
||||
use parking_lot::Mutex;
|
||||
use project::Fs;
|
||||
use settings::{self, KeymapFile, Settings, SettingsFileContent};
|
||||
use smol::process::Command;
|
||||
use std::{env, fs, path::PathBuf, sync::Arc};
|
||||
use std::{env, fs, path::PathBuf, sync::Arc, thread, time::Duration};
|
||||
use theme::{ThemeRegistry, DEFAULT_THEME_NAME};
|
||||
use util::ResultExt;
|
||||
use workspace::{self, AppState, OpenNew, OpenPaths};
|
||||
|
@ -26,7 +33,7 @@ use zed::{
|
|||
fn main() {
|
||||
init_logger();
|
||||
|
||||
let app = gpui::App::new(Assets).unwrap();
|
||||
let mut app = gpui::App::new(Assets).unwrap();
|
||||
load_embedded_fonts(&app);
|
||||
|
||||
let fs = Arc::new(RealFs);
|
||||
|
@ -87,6 +94,18 @@ fn main() {
|
|||
})
|
||||
};
|
||||
|
||||
let (cli_connections_tx, mut cli_connections_rx) = mpsc::unbounded();
|
||||
app.on_open_urls(move |urls, _| {
|
||||
if let Some(server_name) = urls.first().and_then(|url| url.strip_prefix("zed-cli://")) {
|
||||
if let Some(cli_connection) = connect_to_cli(server_name).log_err() {
|
||||
cli_connections_tx
|
||||
.unbounded_send(cli_connection)
|
||||
.map_err(|_| anyhow!("no listener for cli connections"))
|
||||
.log_err();
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
app.run(move |cx| {
|
||||
let http = http::client();
|
||||
let client = client::Client::new(http.clone());
|
||||
|
@ -170,13 +189,25 @@ fn main() {
|
|||
|
||||
if stdout_is_a_pty() {
|
||||
cx.platform().activate(true);
|
||||
}
|
||||
|
||||
let paths = collect_path_args();
|
||||
if paths.is_empty() {
|
||||
cx.dispatch_global_action(OpenNew(app_state.clone()));
|
||||
let paths = collect_path_args();
|
||||
if paths.is_empty() {
|
||||
cx.dispatch_global_action(OpenNew(app_state.clone()));
|
||||
} else {
|
||||
cx.dispatch_global_action(OpenPaths { paths, app_state });
|
||||
}
|
||||
} else {
|
||||
cx.dispatch_global_action(OpenPaths { paths, app_state });
|
||||
if let Ok(Some(connection)) = cli_connections_rx.try_next() {
|
||||
cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx))
|
||||
.detach();
|
||||
} else {
|
||||
cx.dispatch_global_action(OpenNew(app_state.clone()));
|
||||
}
|
||||
cx.spawn(|cx| async move {
|
||||
while let Some(connection) = cli_connections_rx.next().await {
|
||||
handle_cli_connection(connection, app_state.clone(), cx.clone()).await;
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -292,3 +323,117 @@ fn load_config_files(
|
|||
.detach();
|
||||
rx
|
||||
}
|
||||
|
||||
fn connect_to_cli(
|
||||
server_name: &str,
|
||||
) -> Result<(mpsc::Receiver<CliRequest>, IpcSender<CliResponse>)> {
|
||||
let handshake_tx = cli::ipc::IpcSender::<IpcHandshake>::connect(server_name.to_string())
|
||||
.context("error connecting to cli")?;
|
||||
let (request_tx, request_rx) = ipc::channel::<CliRequest>()?;
|
||||
let (response_tx, response_rx) = ipc::channel::<CliResponse>()?;
|
||||
|
||||
handshake_tx
|
||||
.send(IpcHandshake {
|
||||
requests: request_tx,
|
||||
responses: response_rx,
|
||||
})
|
||||
.context("error sending ipc handshake")?;
|
||||
|
||||
let (mut async_request_tx, async_request_rx) =
|
||||
futures::channel::mpsc::channel::<CliRequest>(16);
|
||||
thread::spawn(move || {
|
||||
while let Ok(cli_request) = request_rx.recv() {
|
||||
if smol::block_on(async_request_tx.send(cli_request)).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok::<_, anyhow::Error>(())
|
||||
});
|
||||
|
||||
Ok((async_request_rx, response_tx))
|
||||
}
|
||||
|
||||
async fn handle_cli_connection(
|
||||
(mut requests, responses): (mpsc::Receiver<CliRequest>, IpcSender<CliResponse>),
|
||||
app_state: Arc<AppState>,
|
||||
mut cx: AsyncAppContext,
|
||||
) {
|
||||
if let Some(request) = requests.next().await {
|
||||
match request {
|
||||
CliRequest::Open { paths, wait } => {
|
||||
let (workspace, items) = cx
|
||||
.update(|cx| workspace::open_paths(&paths, &app_state, cx))
|
||||
.await;
|
||||
|
||||
let mut errored = false;
|
||||
let mut futures = Vec::new();
|
||||
cx.update(|cx| {
|
||||
for (item, path) in items.into_iter().zip(&paths) {
|
||||
match item {
|
||||
Some(Ok(item)) => {
|
||||
let released = oneshot::channel();
|
||||
item.on_release(
|
||||
cx,
|
||||
Box::new(move |_| {
|
||||
let _ = released.0.send(());
|
||||
}),
|
||||
)
|
||||
.detach();
|
||||
futures.push(released.1);
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
responses
|
||||
.send(CliResponse::Stderr {
|
||||
message: format!("error opening {:?}: {}", path, err),
|
||||
})
|
||||
.log_err();
|
||||
errored = true;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if wait {
|
||||
let background = cx.background();
|
||||
let wait = async move {
|
||||
if paths.is_empty() {
|
||||
let (done_tx, done_rx) = oneshot::channel();
|
||||
let _subscription = cx.update(|cx| {
|
||||
cx.observe_release(&workspace, move |_, _| {
|
||||
let _ = done_tx.send(());
|
||||
})
|
||||
});
|
||||
drop(workspace);
|
||||
let _ = done_rx.await;
|
||||
} else {
|
||||
let _ = futures::future::try_join_all(futures).await;
|
||||
};
|
||||
}
|
||||
.fuse();
|
||||
futures::pin_mut!(wait);
|
||||
|
||||
loop {
|
||||
// Repeatedly check if CLI is still open to avoid wasting resources
|
||||
// waiting for files or workspaces to close.
|
||||
let mut timer = background.timer(Duration::from_secs(1)).fuse();
|
||||
futures::select_biased! {
|
||||
_ = wait => break,
|
||||
_ = timer => {
|
||||
if responses.send(CliResponse::Ping).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
responses
|
||||
.send(CliResponse::Exit {
|
||||
status: if errored { 1 } else { 0 },
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,12 @@ pub fn menus(state: &Arc<AppState>) -> Vec<Menu<'static>> {
|
|||
action: Box::new(super::About),
|
||||
},
|
||||
MenuItem::Separator,
|
||||
MenuItem::Action {
|
||||
name: "Install CLI",
|
||||
keystroke: None,
|
||||
action: Box::new(super::InstallCommandLineInterface),
|
||||
},
|
||||
MenuItem::Separator,
|
||||
MenuItem::Action {
|
||||
name: "Quit",
|
||||
keystroke: Some("cmd-q"),
|
||||
|
|
|
@ -4,6 +4,7 @@ pub mod settings_file;
|
|||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub mod test;
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use breadcrumbs::Breadcrumbs;
|
||||
use chat_panel::ChatPanel;
|
||||
pub use client;
|
||||
|
@ -15,7 +16,7 @@ use gpui::{
|
|||
actions,
|
||||
geometry::vector::vec2f,
|
||||
platform::{WindowBounds, WindowOptions},
|
||||
ModelHandle, ViewContext,
|
||||
AsyncAppContext, ModelHandle, ViewContext,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
pub use lsp;
|
||||
|
@ -25,7 +26,10 @@ use project_panel::ProjectPanel;
|
|||
use search::{BufferSearchBar, ProjectSearchBar};
|
||||
use serde_json::to_string_pretty;
|
||||
use settings::Settings;
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use util::ResultExt;
|
||||
pub use workspace;
|
||||
use workspace::{AppState, Workspace, WorkspaceParams};
|
||||
|
@ -38,7 +42,8 @@ actions!(
|
|||
DebugElements,
|
||||
OpenSettings,
|
||||
IncreaseBufferFontSize,
|
||||
DecreaseBufferFontSize
|
||||
DecreaseBufferFontSize,
|
||||
InstallCommandLineInterface,
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -66,6 +71,10 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
|
|||
cx.refresh_windows();
|
||||
});
|
||||
});
|
||||
cx.add_global_action(move |_: &InstallCommandLineInterface, cx| {
|
||||
cx.spawn(|cx| async move { install_cli(&cx).await.context("error creating CLI symlink") })
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
|
||||
|
@ -230,6 +239,54 @@ fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {
|
|||
cx.platform().quit();
|
||||
}
|
||||
|
||||
async fn install_cli(cx: &AsyncAppContext) -> Result<()> {
|
||||
let cli_path = cx.platform().path_for_auxiliary_executable("cli")?;
|
||||
let link_path = Path::new("/usr/local/bin/zed");
|
||||
let bin_dir_path = link_path.parent().unwrap();
|
||||
|
||||
// Don't re-create symlink if it points to the same CLI binary.
|
||||
if smol::fs::read_link(link_path).await.ok().as_ref() == Some(&cli_path) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// If the symlink is not there or is outdated, first try replacing it
|
||||
// without escalating.
|
||||
smol::fs::remove_file(link_path).await.log_err();
|
||||
if smol::fs::unix::symlink(&cli_path, link_path)
|
||||
.await
|
||||
.log_err()
|
||||
.is_some()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// The symlink could not be created, so use osascript with admin privileges
|
||||
// to create it.
|
||||
let status = smol::process::Command::new("osascript")
|
||||
.args([
|
||||
"-e",
|
||||
&format!(
|
||||
"do shell script \" \
|
||||
mkdir -p \'{}\' && \
|
||||
ln -sf \'{}\' \'{}\' \
|
||||
\" with administrator privileges",
|
||||
bin_dir_path.to_string_lossy(),
|
||||
cli_path.to_string_lossy(),
|
||||
link_path.to_string_lossy(),
|
||||
),
|
||||
])
|
||||
.stdout(smol::process::Stdio::inherit())
|
||||
.stderr(smol::process::Stdio::inherit())
|
||||
.output()
|
||||
.await?
|
||||
.status;
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("error running osascript"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -4,24 +4,33 @@ set -e
|
|||
|
||||
export ZED_BUNDLE=true
|
||||
|
||||
# Install cargo-bundle 0.5.0 if it's not already installed
|
||||
echo "Installing cargo bundle"
|
||||
cargo install cargo-bundle --version 0.5.0
|
||||
|
||||
# Deal with versions of macOS that don't include libstdc++ headers
|
||||
export CXXFLAGS="-stdlib=libc++"
|
||||
|
||||
# Build the app bundle for x86_64
|
||||
pushd crates/zed > /dev/null
|
||||
cargo bundle --release --target x86_64-apple-darwin
|
||||
popd > /dev/null
|
||||
echo "Compiling binaries"
|
||||
cargo build --release --package zed --target aarch64-apple-darwin
|
||||
cargo build --release --package zed --target x86_64-apple-darwin
|
||||
cargo build --release --package cli --target aarch64-apple-darwin
|
||||
cargo build --release --package cli --target x86_64-apple-darwin
|
||||
|
||||
# Build the binary for aarch64 (Apple M1)
|
||||
cargo build --release --target aarch64-apple-darwin
|
||||
echo "Creating application bundle"
|
||||
(cd crates/zed && cargo bundle --release --target x86_64-apple-darwin)
|
||||
|
||||
# Replace the bundle's binary with a "fat binary" that combines the two architecture-specific binaries
|
||||
lipo -create target/x86_64-apple-darwin/release/Zed target/aarch64-apple-darwin/release/Zed -output target/x86_64-apple-darwin/release/bundle/osx/Zed.app/Contents/MacOS/zed
|
||||
echo "Creating fat binaries"
|
||||
lipo \
|
||||
-create \
|
||||
target/{x86_64-apple-darwin,aarch64-apple-darwin}/release/Zed \
|
||||
-output \
|
||||
target/x86_64-apple-darwin/release/bundle/osx/Zed.app/Contents/MacOS/zed
|
||||
lipo \
|
||||
-create \
|
||||
target/{x86_64-apple-darwin,aarch64-apple-darwin}/release/cli \
|
||||
-output \
|
||||
target/x86_64-apple-darwin/release/bundle/osx/Zed.app/Contents/MacOS/cli
|
||||
|
||||
# Sign the app bundle with an ad-hoc signature so it runs on the M1. We need a real certificate but this works for now.
|
||||
if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then
|
||||
echo "Signing bundle with Apple-issued certificate"
|
||||
security create-keychain -p $MACOS_CERTIFICATE_PASSWORD zed.keychain || echo ""
|
||||
|
@ -39,7 +48,6 @@ else
|
|||
codesign --force --deep --sign - target/x86_64-apple-darwin/release/bundle/osx/Zed.app -v
|
||||
fi
|
||||
|
||||
# Create a DMG
|
||||
echo "Creating DMG"
|
||||
mkdir -p target/release
|
||||
hdiutil create -volname Zed -srcfolder target/x86_64-apple-darwin/release/bundle/osx -ov -format UDZO target/release/Zed.dmg
|
||||
|
|
Loading…
Reference in a new issue