Detailed changes
@@ -92,7 +92,7 @@ jobs:
run: script/generate-licenses
- name: Create app bundle
- run: script/bundle -2
+ run: script/bundle
- name: Upload Zed Nightly
run: script/upload-nightly
@@ -38,22 +38,13 @@ dependencies = [
"workspace2",
]
-[[package]]
-name = "addr2line"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
-dependencies = [
- "gimli 0.26.2",
-]
-
[[package]]
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
- "gimli 0.28.0",
+ "gimli",
]
[[package]]
@@ -237,12 +228,6 @@ dependencies = [
"pkg-config",
]
-[[package]]
-name = "ambient-authority"
-version = "0.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec8ad6edb4840b78c5c3d88de606b22252d552b55f3a4699fbb10fc070ec3049"
-
[[package]]
name = "android-tzdata"
version = "0.1.1"
@@ -368,7 +353,7 @@ dependencies = [
"collections",
"ctor",
"editor",
- "env_logger 0.9.3",
+ "env_logger",
"fs",
"futures 0.3.28",
"gpui",
@@ -408,7 +393,7 @@ dependencies = [
"collections",
"ctor",
"editor2",
- "env_logger 0.9.3",
+ "env_logger",
"fs2",
"futures 0.3.28",
"gpui2",
@@ -913,12 +898,12 @@ version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
- "addr2line 0.21.0",
+ "addr2line",
"cc",
"cfg-if 1.0.0",
"libc",
"miniz_oxide 0.7.1",
- "object 0.32.1",
+ "object",
"rustc-demangle",
]
@@ -1307,71 +1292,6 @@ dependencies = [
"util",
]
-[[package]]
-name = "cap-fs-ext"
-version = "0.26.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b0e103ce36d217d568903ad27b14ec2238ecb5d65bad2e756a8f3c0d651506e"
-dependencies = [
- "cap-primitives",
- "cap-std",
- "io-lifetimes 0.7.5",
- "windows-sys 0.36.1",
-]
-
-[[package]]
-name = "cap-primitives"
-version = "0.26.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af3f336aa91cce16033ed3c94ac91d98956c49b420e6d6cd0dd7d0e386a57085"
-dependencies = [
- "ambient-authority",
- "fs-set-times",
- "io-extras",
- "io-lifetimes 0.7.5",
- "ipnet",
- "maybe-owned",
- "rustix 0.35.16",
- "winapi-util",
- "windows-sys 0.36.1",
- "winx",
-]
-
-[[package]]
-name = "cap-rand"
-version = "0.26.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d14b9606aa9550d34651bc481443203bc014237bdb992d201d2afa62d2ec6dea"
-dependencies = [
- "ambient-authority",
- "rand 0.8.5",
-]
-
-[[package]]
-name = "cap-std"
-version = "0.26.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9d6e70b626eceac9d6fc790fe2d72cc3f2f7bc3c35f467690c54a526b0f56db"
-dependencies = [
- "cap-primitives",
- "io-extras",
- "io-lifetimes 0.7.5",
- "ipnet",
- "rustix 0.35.16",
-]
-
-[[package]]
-name = "cap-time-ext"
-version = "0.26.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3a0524f7c4cff2ea547ae2b652bf7a348fd3e48f76556dc928d8b45ab2f1d50"
-dependencies = [
- "cap-primitives",
- "once_cell",
- "rustix 0.35.16",
- "winx",
-]
-
[[package]]
name = "castaway"
version = "0.1.2"
@@ -1783,7 +1703,7 @@ dependencies = [
"ctor",
"dashmap",
"editor",
- "env_logger 0.9.3",
+ "env_logger",
"envy",
"fs",
"futures 0.3.28",
@@ -1856,7 +1776,7 @@ dependencies = [
"ctor",
"dashmap",
"editor2",
- "env_logger 0.9.3",
+ "env_logger",
"envy",
"fs2",
"futures 0.3.28",
@@ -2037,7 +1957,7 @@ dependencies = [
"collections",
"ctor",
"editor",
- "env_logger 0.9.3",
+ "env_logger",
"fuzzy",
"gpui",
"language",
@@ -2059,7 +1979,7 @@ dependencies = [
"collections",
"ctor",
"editor2",
- "env_logger 0.9.3",
+ "env_logger",
"fuzzy2",
"go_to_line2",
"gpui2",
@@ -2352,15 +2272,6 @@ dependencies = [
"windows 0.46.0",
]
-[[package]]
-name = "cpp_demangle"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f"
-dependencies = [
- "cfg-if 1.0.0",
-]
-
[[package]]
name = "cpufeatures"
version = "0.2.9"
@@ -2370,41 +2281,12 @@ dependencies = [
"libc",
]
-[[package]]
-name = "cranelift-bforest"
-version = "0.89.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "593b398dd0c5b1e2e3a9c3dae8584e287894ea84e361949ad506376e99196265"
-dependencies = [
- "cranelift-entity 0.89.2",
-]
-
[[package]]
name = "cranelift-bforest"
version = "0.103.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7"
dependencies = [
- "cranelift-entity 0.103.0",
-]
-
-[[package]]
-name = "cranelift-codegen"
-version = "0.89.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afc0d8faabd099ea15ab33d49d150e5572c04cfeb95d675fd41286739b754629"
-dependencies = [
- "arrayvec 0.7.4",
- "bumpalo",
- "cranelift-bforest 0.89.2",
- "cranelift-codegen-meta 0.89.2",
- "cranelift-codegen-shared 0.89.2",
- "cranelift-entity 0.89.2",
- "cranelift-isle 0.89.2",
- "gimli 0.26.2",
- "log",
- "regalloc2 0.4.2",
- "smallvec",
- "target-lexicon",
+ "cranelift-entity",
]
[[package]]
@@ -2413,43 +2295,28 @@ version = "0.103.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7"
dependencies = [
"bumpalo",
- "cranelift-bforest 0.103.0",
- "cranelift-codegen-meta 0.103.0",
- "cranelift-codegen-shared 0.103.0",
+ "cranelift-bforest",
+ "cranelift-codegen-meta",
+ "cranelift-codegen-shared",
"cranelift-control",
- "cranelift-entity 0.103.0",
- "cranelift-isle 0.103.0",
- "gimli 0.28.0",
+ "cranelift-entity",
+ "cranelift-isle",
+ "gimli",
"hashbrown 0.14.0",
"log",
- "regalloc2 0.9.3",
+ "regalloc2",
"smallvec",
"target-lexicon",
]
-[[package]]
-name = "cranelift-codegen-meta"
-version = "0.89.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ac1669e42579476f001571d6ba4b825fac686282c97b88b18f8e34242066a81"
-dependencies = [
- "cranelift-codegen-shared 0.89.2",
-]
-
[[package]]
name = "cranelift-codegen-meta"
version = "0.103.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7"
dependencies = [
- "cranelift-codegen-shared 0.103.0",
+ "cranelift-codegen-shared",
]
-[[package]]
-name = "cranelift-codegen-shared"
-version = "0.89.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2a1b1eef9640ab72c1e7b583ac678083855a509da34b4b4378bd99954127c20"
-
[[package]]
name = "cranelift-codegen-shared"
version = "0.103.0"
@@ -2463,15 +2330,6 @@ dependencies = [
"arbitrary",
]
-[[package]]
-name = "cranelift-entity"
-version = "0.89.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eea4e17c3791fd8134640b26242a9ddbd7c67db78f0bad98cb778bf563ef81a0"
-dependencies = [
- "serde",
-]
-
[[package]]
name = "cranelift-entity"
version = "0.103.0"
@@ -2481,90 +2339,45 @@ dependencies = [
"serde_derive",
]
-[[package]]
-name = "cranelift-frontend"
-version = "0.89.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fca1474b5302348799656d43a40eacd716a3b46169405a3af812832c9edf77b4"
-dependencies = [
- "cranelift-codegen 0.89.2",
- "log",
- "smallvec",
- "target-lexicon",
-]
-
[[package]]
name = "cranelift-frontend"
version = "0.103.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7"
dependencies = [
- "cranelift-codegen 0.103.0",
+ "cranelift-codegen",
"log",
"smallvec",
"target-lexicon",
]
-[[package]]
-name = "cranelift-isle"
-version = "0.89.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77aa537f020ea43483100153278e7215d41695bdcef9eea6642d122675f64249"
-
[[package]]
name = "cranelift-isle"
version = "0.103.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7"
-[[package]]
-name = "cranelift-native"
-version = "0.89.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bdc6b65241a95b7d8eafbf4e114c082e49b80162a2dcd9c6bcc5989c3310c9e"
-dependencies = [
- "cranelift-codegen 0.89.2",
- "libc",
- "target-lexicon",
-]
-
[[package]]
name = "cranelift-native"
version = "0.103.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7"
dependencies = [
- "cranelift-codegen 0.103.0",
+ "cranelift-codegen",
"libc",
"target-lexicon",
]
-[[package]]
-name = "cranelift-wasm"
-version = "0.89.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb6359f606a1c80ccaa04fae9dbbb504615ec7a49b6c212b341080fff7a65dd"
-dependencies = [
- "cranelift-codegen 0.89.2",
- "cranelift-entity 0.89.2",
- "cranelift-frontend 0.89.2",
- "itertools 0.10.5",
- "log",
- "smallvec",
- "wasmparser 0.92.0",
- "wasmtime-types 2.0.2",
-]
-
[[package]]
name = "cranelift-wasm"
version = "0.103.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7"
dependencies = [
- "cranelift-codegen 0.103.0",
- "cranelift-entity 0.103.0",
- "cranelift-frontend 0.103.0",
+ "cranelift-codegen",
+ "cranelift-entity",
+ "cranelift-frontend",
"itertools 0.10.5",
"log",
"smallvec",
- "wasmparser 0.118.1",
- "wasmtime-types 16.0.0",
+ "wasmparser",
+ "wasmtime-types",
]
[[package]]
@@ -2738,7 +2551,7 @@ dependencies = [
"anyhow",
"async-trait",
"collections",
- "env_logger 0.9.3",
+ "env_logger",
"gpui",
"indoc",
"lazy_static",
@@ -2760,7 +2573,7 @@ dependencies = [
"anyhow",
"async-trait",
"collections",
- "env_logger 0.9.3",
+ "env_logger",
"gpui2",
"indoc",
"lazy_static",
@@ -2950,16 +2763,6 @@ dependencies = [
"subtle",
]
-[[package]]
-name = "directories-next"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc"
-dependencies = [
- "cfg-if 1.0.0",
- "dirs-sys-next",
-]
-
[[package]]
name = "dirs"
version = "3.0.2"
@@ -3066,7 +2869,7 @@ dependencies = [
"ctor",
"db",
"drag_and_drop",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"fuzzy",
"git",
@@ -3118,7 +2921,7 @@ dependencies = [
"copilot2",
"ctor",
"db2",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"fuzzy2",
"git3",
@@ -3196,19 +2999,6 @@ dependencies = [
"termcolor",
]
-[[package]]
-name = "env_logger"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
-dependencies = [
- "humantime",
- "is-terminal 0.4.10",
- "log",
- "regex",
- "termcolor",
-]
-
[[package]]
name = "envy"
version = "0.4.2"
@@ -3233,17 +3023,6 @@ dependencies = [
"serde",
]
-[[package]]
-name = "errno"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "winapi 0.3.9",
-]
-
[[package]]
name = "errno"
version = "0.3.3"
@@ -3431,16 +3210,6 @@ dependencies = [
"workspace2",
]
-[[package]]
-name = "file-per-thread-logger"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866"
-dependencies = [
- "env_logger 0.10.1",
- "log",
-]
-
[[package]]
name = "file_finder"
version = "0.1.0"
@@ -3448,7 +3217,7 @@ dependencies = [
"collections",
"ctor",
"editor",
- "env_logger 0.9.3",
+ "env_logger",
"fuzzy",
"gpui",
"language",
@@ -3471,7 +3240,7 @@ dependencies = [
"collections",
"ctor",
"editor2",
- "env_logger 0.9.3",
+ "env_logger",
"fuzzy2",
"gpui2",
"language2",
@@ -3660,17 +3429,6 @@ dependencies = [
"util",
]
-[[package]]
-name = "fs-set-times"
-version = "0.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a267b6a9304912e018610d53fe07115d8b530b160e85db4d2d3a59f3ddde1aec"
-dependencies = [
- "io-lifetimes 0.7.5",
- "rustix 0.35.16",
- "windows-sys 0.36.1",
-]
-
[[package]]
name = "fs2"
version = "0.1.0"
@@ -3894,15 +3652,6 @@ dependencies = [
"util",
]
-[[package]]
-name = "fxhash"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
-dependencies = [
- "byteorder",
-]
-
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -3945,17 +3694,6 @@ dependencies = [
"weezl",
]
-[[package]]
-name = "gimli"
-version = "0.26.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
-dependencies = [
- "fallible-iterator 0.2.0",
- "indexmap 1.9.3",
- "stable_deref_trait",
-]
-
[[package]]
name = "gimli"
version = "0.28.0"
@@ -4101,7 +3839,7 @@ dependencies = [
"ctor",
"derive_more",
"dhat",
- "env_logger 0.9.3",
+ "env_logger",
"etagere",
"font-kit",
"foreign-types",
@@ -4164,7 +3902,7 @@ dependencies = [
"ctor",
"derive_more",
"dhat",
- "env_logger 0.9.3",
+ "env_logger",
"etagere",
"font-kit",
"foreign-types",
@@ -4347,15 +4085,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "hermit-abi"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
-dependencies = [
- "libc",
-]
-
[[package]]
name = "hermit-abi"
version = "0.3.3"
@@ -4652,26 +4381,6 @@ dependencies = [
"cfg-if 1.0.0",
]
-[[package]]
-name = "io-extras"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a5d8c2ab5becd8720e30fd25f8fa5500d8dc3fceadd8378f05859bd7b46fc49"
-dependencies = [
- "io-lifetimes 0.7.5",
- "windows-sys 0.36.1",
-]
-
-[[package]]
-name = "io-lifetimes"
-version = "0.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074"
-dependencies = [
- "libc",
- "windows-sys 0.42.0",
-]
-
[[package]]
name = "io-lifetimes"
version = "1.0.11"
@@ -4717,29 +4426,6 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
-[[package]]
-name = "is-terminal"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d508111813f9af3afd2f92758f77e4ed2cc9371b642112c6a48d22eb73105c5"
-dependencies = [
- "hermit-abi 0.2.6",
- "io-lifetimes 0.7.5",
- "rustix 0.35.16",
- "windows-sys 0.36.1",
-]
-
-[[package]]
-name = "is-terminal"
-version = "0.4.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
-dependencies = [
- "hermit-abi 0.3.3",
- "rustix 0.38.21",
- "windows-sys 0.52.0",
-]
-
[[package]]
name = "isahc"
version = "1.7.2"
@@ -4791,26 +4477,6 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
-[[package]]
-name = "ittapi"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25a5c0b993601cad796222ea076565c5d9f337d35592f8622c753724f06d7271"
-dependencies = [
- "anyhow",
- "ittapi-sys",
- "log",
-]
-
-[[package]]
-name = "ittapi-sys"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7b5e473765060536a660eed127f758cf1a810c73e49063264959c60d1727d9"
-dependencies = [
- "cc",
-]
-
[[package]]
name = "jni"
version = "0.19.0"
@@ -4959,7 +4625,7 @@ dependencies = [
"clock",
"collections",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"fs",
"futures 0.3.28",
"fuzzy",
@@ -5014,7 +4680,7 @@ dependencies = [
"clock",
"collections",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"fuzzy2",
"git3",
@@ -5100,7 +4766,7 @@ dependencies = [
"client",
"collections",
"editor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"gpui",
"language",
@@ -5123,7 +4789,7 @@ dependencies = [
"client2",
"collections",
"editor2",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"gpui2",
"language2",
@@ -5262,12 +4928,6 @@ dependencies = [
"syn 2.0.37",
]
-[[package]]
-name = "linux-raw-sys"
-version = "0.0.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
-
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
@@ -5403,7 +5063,7 @@ dependencies = [
"async-pipe",
"collections",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"gpui",
"log",
@@ -5438,7 +5098,7 @@ dependencies = [
"async-pipe",
"collections",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"gpui2",
"log",
@@ -5511,12 +5171,6 @@ dependencies = [
"rawpointer",
]
-[[package]]
-name = "maybe-owned"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4"
-
[[package]]
name = "md-5"
version = "0.10.5"
@@ -5761,7 +5415,7 @@ dependencies = [
"convert_case 0.6.0",
"copilot",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"git",
"gpui",
@@ -5809,7 +5463,7 @@ dependencies = [
"convert_case 0.6.0",
"copilot2",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"git3",
"gpui2",
@@ -6280,18 +5934,6 @@ dependencies = [
"cc",
]
-[[package]]
-name = "object"
-version = "0.29.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
-dependencies = [
- "crc32fast",
- "hashbrown 0.12.3",
- "indexmap 1.9.3",
- "memchr",
-]
-
[[package]]
name = "object"
version = "0.32.1"
@@ -6678,7 +6320,7 @@ version = "0.1.0"
dependencies = [
"ctor",
"editor",
- "env_logger 0.9.3",
+ "env_logger",
"gpui",
"menu",
"parking_lot 0.11.2",
@@ -6695,7 +6337,7 @@ version = "0.1.0"
dependencies = [
"ctor",
"editor2",
- "env_logger 0.9.3",
+ "env_logger",
"gpui2",
"menu2",
"parking_lot 0.11.2",
@@ -6814,22 +6456,6 @@ dependencies = [
"syn 1.0.109",
]
-[[package]]
-name = "plugin_runtime"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "bincode",
- "pollster",
- "serde",
- "serde_derive",
- "serde_json",
- "smol",
- "wasi-common",
- "wasmtime 2.0.2",
- "wasmtime-wasi",
-]
-
[[package]]
name = "png"
version = "0.16.8"
@@ -7026,7 +6652,7 @@ dependencies = [
"copilot",
"ctor",
"db",
- "env_logger 0.9.3",
+ "env_logger",
"fs",
"fsevent",
"futures 0.3.28",
@@ -7081,7 +6707,7 @@ dependencies = [
"copilot2",
"ctor",
"db2",
- "env_logger 0.9.3",
+ "env_logger",
"fs2",
"fsevent",
"futures 0.3.28",
@@ -7384,19 +7010,7 @@ dependencies = [
]
[[package]]
-name = "quick_action_bar"
-version = "0.1.0"
-dependencies = [
- "assistant",
- "editor",
- "gpui",
- "search",
- "theme",
- "workspace",
-]
-
-[[package]]
-name = "quick_action_bar2"
+name = "quick_action_bar2"
version = "0.1.0"
dependencies = [
"assistant2",
@@ -7649,18 +7263,6 @@ dependencies = [
"syn 1.0.109",
]
-[[package]]
-name = "regalloc2"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5"
-dependencies = [
- "fxhash",
- "log",
- "slice-group-by",
- "smallvec",
-]
-
[[package]]
name = "regalloc2"
version = "0.9.3"
@@ -7956,7 +7558,7 @@ dependencies = [
"clock",
"collections",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"gpui",
"parking_lot 0.11.2",
@@ -7987,7 +7589,7 @@ dependencies = [
"clock",
"collections",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"gpui2",
"parking_lot 0.11.2",
@@ -8135,22 +7737,6 @@ dependencies = [
"semver",
]
-[[package]]
-name = "rustix"
-version = "0.35.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5363f616a5244fd47fc1dd0a0b24c28a5c0154f5010c16332a7ad6f78f2e8b62"
-dependencies = [
- "bitflags 1.3.2",
- "errno 0.2.8",
- "io-lifetimes 0.7.5",
- "itoa",
- "libc",
- "linux-raw-sys 0.0.46",
- "once_cell",
- "windows-sys 0.42.0",
-]
-
[[package]]
name = "rustix"
version = "0.37.23"
@@ -8158,8 +7744,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
dependencies = [
"bitflags 1.3.2",
- "errno 0.3.3",
- "io-lifetimes 1.0.11",
+ "errno",
+ "io-lifetimes",
"libc",
"linux-raw-sys 0.3.8",
"windows-sys 0.48.0",
@@ -8172,7 +7758,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
dependencies = [
"bitflags 2.4.1",
- "errno 0.3.3",
+ "errno",
"libc",
"linux-raw-sys 0.4.12",
"windows-sys 0.48.0",
@@ -8548,7 +8134,7 @@ dependencies = [
"collections",
"ctor",
"editor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"globset",
"gpui",
@@ -8601,7 +8187,7 @@ dependencies = [
"client2",
"collections",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"futures 0.3.28",
"globset",
"gpui2",
@@ -9491,7 +9077,7 @@ version = "0.1.0"
dependencies = [
"arrayvec 0.7.4",
"ctor",
- "env_logger 0.9.3",
+ "env_logger",
"log",
"rand 0.8.5",
]
@@ -129,7 +129,6 @@ members = [
"crates/welcome2",
"crates/xtask",
"crates/zed",
- "crates/zed2",
"crates/zed-actions",
"crates/zed_actions2"
]
@@ -1,5 +1,4 @@
[package]
-authors = ["Nathan Sobo <nathansobo@gmail.com>"]
description = "The fast, collaborative code editor."
edition = "2021"
name = "zed"
@@ -12,71 +11,69 @@ path = "src/zed.rs"
doctest = false
[[bin]]
-name = "Zed"
+name = "zed"
path = "src/main.rs"
-[[example]]
-name = "semantic_index_eval"
-
[dependencies]
-audio = { path = "../audio" }
-activity_indicator = { path = "../activity_indicator" }
-auto_update = { path = "../auto_update" }
-breadcrumbs = { path = "../breadcrumbs" }
-call = { path = "../call" }
-channel = { path = "../channel" }
+ai = { package = "ai2", path = "../ai2"}
+audio = { package = "audio2", path = "../audio2" }
+activity_indicator = { package = "activity_indicator2", path = "../activity_indicator2"}
+auto_update = { package = "auto_update2", path = "../auto_update2" }
+breadcrumbs = { package = "breadcrumbs2", path = "../breadcrumbs2" }
+call = { package = "call2", path = "../call2" }
+channel = { package = "channel2", path = "../channel2" }
cli = { path = "../cli" }
-collab_ui = { path = "../collab_ui" }
+collab_ui = { package = "collab_ui2", path = "../collab_ui2" }
collections = { path = "../collections" }
-command_palette = { path = "../command_palette" }
-component_test = { path = "../component_test" }
-context_menu = { path = "../context_menu" }
-client = { path = "../client" }
-clock = { path = "../clock" }
-copilot = { path = "../copilot" }
-copilot_button = { path = "../copilot_button" }
-diagnostics = { path = "../diagnostics" }
-db = { path = "../db" }
-editor = { path = "../editor" }
-feedback = { path = "../feedback" }
-file_finder = { path = "../file_finder" }
-search = { path = "../search" }
-fs = { path = "../fs" }
+command_palette = { package="command_palette2", path = "../command_palette2" }
+# component_test = { path = "../component_test" }
+client = { package = "client2", path = "../client2" }
+# clock = { path = "../clock" }
+copilot = { package = "copilot2", path = "../copilot2" }
+copilot_button = { package = "copilot_button2", path = "../copilot_button2" }
+diagnostics = { package = "diagnostics2", path = "../diagnostics2" }
+db = { package = "db2", path = "../db2" }
+editor = { package="editor2", path = "../editor2" }
+feedback = { package="feedback2", path = "../feedback2" }
+file_finder = { package="file_finder2", path = "../file_finder2" }
+search = { package = "search2", path = "../search2" }
+fs = { package = "fs2", path = "../fs2" }
fsevent = { path = "../fsevent" }
-fuzzy = { path = "../fuzzy" }
-go_to_line = { path = "../go_to_line" }
-gpui = { path = "../gpui" }
-install_cli = { path = "../install_cli" }
-journal = { path = "../journal" }
-language = { path = "../language" }
-language_selector = { path = "../language_selector" }
-lsp = { path = "../lsp" }
-language_tools = { path = "../language_tools" }
+go_to_line = { package = "go_to_line2", path = "../go_to_line2" }
+gpui = { package = "gpui2", path = "../gpui2" }
+install_cli = { package = "install_cli2", path = "../install_cli2" }
+journal = { package = "journal2", path = "../journal2" }
+language = { package = "language2", path = "../language2" }
+language_selector = { package = "language_selector2", path = "../language_selector2" }
+lsp = { package = "lsp2", path = "../lsp2" }
+menu = { package = "menu2", path = "../menu2" }
+language_tools = { package = "language_tools2", path = "../language_tools2" }
node_runtime = { path = "../node_runtime" }
-notifications = { path = "../notifications" }
-assistant = { path = "../assistant" }
-outline = { path = "../outline" }
-plugin_runtime = { path = "../plugin_runtime",optional = true }
-project = { path = "../project" }
-project_panel = { path = "../project_panel" }
-project_symbols = { path = "../project_symbols" }
-quick_action_bar = { path = "../quick_action_bar" }
-recent_projects = { path = "../recent_projects" }
-rpc = { path = "../rpc" }
-settings = { path = "../settings" }
-feature_flags = { path = "../feature_flags" }
+notifications = { package = "notifications2", path = "../notifications2" }
+assistant = { package = "assistant2", path = "../assistant2" }
+outline = { package = "outline2", path = "../outline2" }
+# plugin_runtime = { path = "../plugin_runtime",optional = true }
+project = { package = "project2", path = "../project2" }
+project_panel = { package = "project_panel2", path = "../project_panel2" }
+project_symbols = { package = "project_symbols2", path = "../project_symbols2" }
+quick_action_bar = { package = "quick_action_bar2", path = "../quick_action_bar2" }
+recent_projects = { package = "recent_projects2", path = "../recent_projects2" }
+rope = { package = "rope2", path = "../rope2"}
+rpc = { package = "rpc2", path = "../rpc2" }
+settings = { package = "settings2", path = "../settings2" }
+feature_flags = { package = "feature_flags2", path = "../feature_flags2" }
sum_tree = { path = "../sum_tree" }
shellexpand = "2.1.0"
-text = { path = "../text" }
-terminal_view = { path = "../terminal_view" }
-theme = { path = "../theme" }
-theme_selector = { path = "../theme_selector" }
+text = { package = "text2", path = "../text2" }
+terminal_view = { package = "terminal_view2", path = "../terminal_view2" }
+theme = { package = "theme2", path = "../theme2" }
+theme_selector = { package = "theme_selector2", path = "../theme_selector2" }
util = { path = "../util" }
-semantic_index = { path = "../semantic_index" }
-vim = { path = "../vim" }
-workspace = { path = "../workspace" }
-welcome = { path = "../welcome" }
-zed-actions = {path = "../zed-actions"}
+semantic_index = { package = "semantic_index2", path = "../semantic_index2" }
+vim = { package = "vim2", path = "../vim2" }
+workspace = { package = "workspace2", path = "../workspace2" }
+welcome = { package = "welcome2", path = "../welcome2" }
+zed_actions = {package = "zed_actions2", path = "../zed_actions2"}
anyhow.workspace = true
async-compression.workspace = true
async-tar = "0.4.2"
@@ -147,20 +144,19 @@ urlencoding = "2.1.2"
uuid.workspace = true
[dev-dependencies]
-ai = { path = "../ai" }
-call = { path = "../call", features = ["test-support"] }
-client = { path = "../client", features = ["test-support"] }
-editor = { path = "../editor", features = ["test-support"] }
-gpui = { path = "../gpui", features = ["test-support"] }
-language = { path = "../language", features = ["test-support"] }
-lsp = { path = "../lsp", features = ["test-support"] }
-project = { path = "../project", features = ["test-support"] }
-rpc = { path = "../rpc", features = ["test-support"] }
-settings = { path = "../settings", features = ["test-support"] }
-text = { path = "../text", features = ["test-support"] }
-util = { path = "../util", features = ["test-support"] }
-workspace = { path = "../workspace", features = ["test-support"] }
-
+call = { package = "call2", path = "../call2", features = ["test-support"] }
+# client = { path = "../client", features = ["test-support"] }
+# editor = { path = "../editor", features = ["test-support"] }
+# gpui = { path = "../gpui", features = ["test-support"] }
+gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
+language = { package = "language2", path = "../language2", features = ["test-support"] }
+# lsp = { path = "../lsp", features = ["test-support"] }
+project = { package = "project2", path = "../project2", features = ["test-support"] }
+# rpc = { path = "../rpc", features = ["test-support"] }
+# settings = { path = "../settings", features = ["test-support"] }
+text = { package = "text2", path = "../text2", features = ["test-support"] }
+# util = { path = "../util", features = ["test-support"] }
+# workspace = { path = "../workspace", features = ["test-support"] }
unindent.workspace = true
[package.metadata.bundle-dev]
@@ -171,6 +167,14 @@ osx_minimum_system_version = "10.15.7"
osx_info_plist_exts = ["resources/info/*"]
osx_url_schemes = ["zed-dev"]
+[package.metadata.bundle-nightly]
+icon = ["resources/app-icon-nightly@2x.png", "resources/app-icon-nightly.png"]
+identifier = "dev.zed.Zed-Nightly"
+name = "Zed Nightly"
+osx_minimum_system_version = "10.15.7"
+osx_info_plist_exts = ["resources/info/*"]
+osx_url_schemes = ["zed-nightly"]
+
[package.metadata.bundle-preview]
icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
identifier = "dev.zed.Zed-Preview"
@@ -3,10 +3,7 @@ use std::process::Command;
fn main() {
println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.15.7");
- if let Ok(value) = std::env::var("ZED_PREVIEW_CHANNEL") {
- println!("cargo:rustc-env=ZED_PREVIEW_CHANNEL={value}");
- }
-
+ println!("cargo:rerun-if-env-changed=ZED_BUNDLE");
if std::env::var("ZED_BUNDLE").ok().as_deref() == Some("true") {
// Find WebRTC.framework in the Frameworks folder when running as part of an application bundle.
println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path/../Frameworks");
@@ -24,31 +21,24 @@ fn main() {
// Register exported Objective-C selectors, protocols, etc
println!("cargo:rustc-link-arg=-Wl,-ObjC");
- // Install dependencies for theme-generation
- let output = Command::new("npm")
- .current_dir("../../styles")
- .args(["install", "--no-save"])
- .output()
- .expect("failed to run npm");
- if !output.status.success() {
- panic!(
- "failed to install theme dependencies {}",
- String::from_utf8_lossy(&output.stderr)
- );
+ // Populate git sha environment variable if git is available
+ println!("cargo:rerun-if-changed=.git/logs/HEAD");
+ if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() {
+ if output.status.success() {
+ let git_sha = String::from_utf8_lossy(&output.stdout);
+ let git_sha = git_sha.trim();
+
+ println!("cargo:rustc-env=ZED_COMMIT_SHA={git_sha}");
+
+ if let Ok(build_profile) = std::env::var("PROFILE") {
+ if build_profile == "release" {
+ // This is currently the best way to make `cargo build ...`'s build script
+ // to print something to stdout without extra verbosity.
+ println!(
+ "cargo:warning=Info: using '{git_sha}' hash for ZED_COMMIT_SHA env var"
+ );
+ }
+ }
+ }
}
-
- // Regenerate themes
- let output = Command::new("npm")
- .current_dir("../../styles")
- .args(["run", "build"])
- .output()
- .expect("failed to run npm");
- if !output.status.success() {
- panic!(
- "build script failed {}",
- String::from_utf8_lossy(&output.stderr)
- );
- }
-
- println!("cargo:rerun-if-changed=../../styles/src");
}
@@ -1,533 +0,0 @@
-use ai::providers::open_ai::OpenAIEmbeddingProvider;
-use anyhow::{anyhow, Result};
-use client::{self, UserStore};
-use gpui::{AsyncAppContext, ModelHandle, Task};
-use language::LanguageRegistry;
-use node_runtime::RealNodeRuntime;
-use project::{Project, RealFs};
-use semantic_index::semantic_index_settings::SemanticIndexSettings;
-use semantic_index::{SearchResult, SemanticIndex};
-use serde::{Deserialize, Serialize};
-use settings::{default_settings, SettingsStore};
-use std::path::{Path, PathBuf};
-use std::process::Command;
-use std::sync::Arc;
-use std::time::{Duration, Instant};
-use std::{cmp, env, fs};
-use util::channel::{RELEASE_CHANNEL, RELEASE_CHANNEL_NAME};
-use util::http::{self};
-use util::paths::EMBEDDINGS_DIR;
-use zed::languages;
-
-#[derive(Deserialize, Clone, Serialize)]
-struct EvaluationQuery {
- query: String,
- matches: Vec<String>,
-}
-
-impl EvaluationQuery {
- fn match_pairs(&self) -> Vec<(PathBuf, u32)> {
- let mut pairs = Vec::new();
- for match_identifier in self.matches.iter() {
- let mut match_parts = match_identifier.split(":");
-
- if let Some(file_path) = match_parts.next() {
- if let Some(row_number) = match_parts.next() {
- pairs.push((PathBuf::from(file_path), row_number.parse::<u32>().unwrap()));
- }
- }
- }
- pairs
- }
-}
-
-#[derive(Deserialize, Clone)]
-struct RepoEval {
- repo: String,
- commit: String,
- assertions: Vec<EvaluationQuery>,
-}
-
-const TMP_REPO_PATH: &str = "eval_repos";
-
-fn parse_eval() -> anyhow::Result<Vec<RepoEval>> {
- let eval_folder = env::current_dir()?
- .as_path()
- .parent()
- .unwrap()
- .join("zed/crates/semantic_index/eval");
-
- let mut repo_evals: Vec<RepoEval> = Vec::new();
- for entry in fs::read_dir(eval_folder)? {
- let file_path = entry.unwrap().path();
- if let Some(extension) = file_path.extension() {
- if extension == "json" {
- if let Ok(file) = fs::read_to_string(file_path) {
- let repo_eval = serde_json::from_str(file.as_str());
-
- match repo_eval {
- Ok(repo_eval) => {
- repo_evals.push(repo_eval);
- }
- Err(err) => {
- println!("Err: {:?}", err);
- }
- }
- }
- }
- }
- }
-
- Ok(repo_evals)
-}
-
-fn clone_repo(repo_eval: RepoEval) -> anyhow::Result<(String, PathBuf)> {
- let repo_name = Path::new(repo_eval.repo.as_str())
- .file_name()
- .unwrap()
- .to_str()
- .unwrap()
- .to_owned()
- .replace(".git", "");
-
- let clone_path = fs::canonicalize(env::current_dir()?)?
- .parent()
- .ok_or(anyhow!("path canonicalization failed"))?
- .parent()
- .unwrap()
- .join(TMP_REPO_PATH);
-
- // Delete Clone Path if already exists
- let _ = fs::remove_dir_all(&clone_path);
- let _ = fs::create_dir(&clone_path);
-
- let _ = Command::new("git")
- .args(["clone", repo_eval.repo.as_str()])
- .current_dir(clone_path.clone())
- .output()?;
- // Update clone path to be new directory housing the repo.
- let clone_path = clone_path.join(repo_name.clone());
- let _ = Command::new("git")
- .args(["checkout", repo_eval.commit.as_str()])
- .current_dir(clone_path.clone())
- .output()?;
-
- Ok((repo_name, clone_path))
-}
-
-fn dcg(hits: Vec<usize>) -> f32 {
- let mut result = 0.0;
- for (idx, hit) in hits.iter().enumerate() {
- result += *hit as f32 / (2.0 + idx as f32).log2();
- }
-
- result
-}
-
-fn get_hits(
- eval_query: EvaluationQuery,
- search_results: Vec<SearchResult>,
- k: usize,
- cx: &AsyncAppContext,
-) -> (Vec<usize>, Vec<usize>) {
- let ideal = vec![1; cmp::min(eval_query.matches.len(), k)];
-
- let mut hits = Vec::new();
- for result in search_results {
- let (path, start_row, end_row) = result.buffer.read_with(cx, |buffer, _cx| {
- let path = buffer.file().unwrap().path().to_path_buf();
- let start_row = buffer.offset_to_point(result.range.start.offset).row;
- let end_row = buffer.offset_to_point(result.range.end.offset).row;
- (path, start_row, end_row)
- });
-
- let match_pairs = eval_query.match_pairs();
- let mut found = 0;
- for (match_path, match_row) in match_pairs {
- if match_path == path {
- if match_row >= start_row && match_row <= end_row {
- found = 1;
- break;
- }
- }
- }
-
- hits.push(found);
- }
-
- // For now, we are calculating ideal_hits a bit different, as technically
- // with overlapping ranges, one match can result in more than result.
- let mut ideal_hits = hits.clone();
- ideal_hits.retain(|x| x == &1);
-
- let ideal = if ideal.len() > ideal_hits.len() {
- ideal
- } else {
- ideal_hits
- };
-
- // Fill ideal to 10 length
- let mut filled_ideal = [0; 10];
- for (idx, i) in ideal.to_vec().into_iter().enumerate() {
- filled_ideal[idx] = i;
- }
-
- (filled_ideal.to_vec(), hits)
-}
-
-fn evaluate_ndcg(hits: Vec<usize>, ideal: Vec<usize>) -> Vec<f32> {
- // NDCG or Normalized Discounted Cumulative Gain, is determined by comparing the relevance of
- // items returned by the search engine relative to the hypothetical ideal.
- // Relevance is represented as a series of booleans, in which each search result returned
- // is identified as being inside the test set of matches (1) or not (0).
-
- // For example, if result 1, 3 and 5 match the 3 relevant results provided
- // actual dcg is calculated against a vector of [1, 0, 1, 0, 1]
- // whereas ideal dcg is calculated against a vector of [1, 1, 1, 0, 0]
- // as this ideal vector assumes the 3 relevant results provided were returned first
- // normalized dcg is then calculated as actual dcg / ideal dcg.
-
- // NDCG ranges from 0 to 1, which higher values indicating better performance
- // Commonly NDCG is expressed as NDCG@k, in which k represents the metric calculated
- // including only the top k values returned.
- // The @k metrics can help you identify, at what point does the relevant results start to fall off.
- // Ie. a NDCG@1 of 0.9 and a NDCG@3 of 0.5 may indicate that the first result returned in usually
- // very high quality, whereas rank results quickly drop off after the first result.
-
- let mut ndcg = Vec::new();
- for idx in 1..(hits.len() + 1) {
- let hits_at_k = hits[0..idx].to_vec();
- let ideal_at_k = ideal[0..idx].to_vec();
-
- let at_k = dcg(hits_at_k.clone()) / dcg(ideal_at_k.clone());
-
- ndcg.push(at_k);
- }
-
- ndcg
-}
-
-fn evaluate_map(hits: Vec<usize>) -> Vec<f32> {
- let mut map_at_k = Vec::new();
-
- let non_zero = hits.iter().sum::<usize>() as f32;
- if non_zero == 0.0 {
- return vec![0.0; hits.len()];
- }
-
- let mut rolling_non_zero = 0.0;
- let mut rolling_map = 0.0;
- for (idx, h) in hits.into_iter().enumerate() {
- rolling_non_zero += h as f32;
- if h == 1 {
- rolling_map += rolling_non_zero / (idx + 1) as f32;
- }
- map_at_k.push(rolling_map / non_zero);
- }
-
- map_at_k
-}
-
-fn evaluate_mrr(hits: Vec<usize>) -> f32 {
- for (idx, h) in hits.into_iter().enumerate() {
- if h == 1 {
- return 1.0 / (idx + 1) as f32;
- }
- }
-
- return 0.0;
-}
-
-fn init_logger() {
- env_logger::init();
-}
-
-#[derive(Serialize)]
-struct QueryMetrics {
- query: EvaluationQuery,
- millis_to_search: Duration,
- ndcg: Vec<f32>,
- map: Vec<f32>,
- mrr: f32,
- hits: Vec<usize>,
- precision: Vec<f32>,
- recall: Vec<f32>,
-}
-
-#[derive(Serialize)]
-struct SummaryMetrics {
- millis_to_search: f32,
- ndcg: Vec<f32>,
- map: Vec<f32>,
- mrr: f32,
- precision: Vec<f32>,
- recall: Vec<f32>,
-}
-
-#[derive(Serialize)]
-struct RepoEvaluationMetrics {
- millis_to_index: Duration,
- query_metrics: Vec<QueryMetrics>,
- repo_metrics: Option<SummaryMetrics>,
-}
-
-impl RepoEvaluationMetrics {
- fn new(millis_to_index: Duration) -> Self {
- RepoEvaluationMetrics {
- millis_to_index,
- query_metrics: Vec::new(),
- repo_metrics: None,
- }
- }
-
- fn save(&self, repo_name: String) -> Result<()> {
- let results_string = serde_json::to_string(&self)?;
- fs::write(format!("./{}_evaluation.json", repo_name), results_string)
- .expect("Unable to write file");
- Ok(())
- }
-
- fn summarize(&mut self) {
- let l = self.query_metrics.len() as f32;
- let millis_to_search: f32 = self
- .query_metrics
- .iter()
- .map(|metrics| metrics.millis_to_search.as_millis())
- .sum::<u128>() as f32
- / l;
-
- let mut ndcg_sum = vec![0.0; 10];
- let mut map_sum = vec![0.0; 10];
- let mut precision_sum = vec![0.0; 10];
- let mut recall_sum = vec![0.0; 10];
- let mut mmr_sum = 0.0;
-
- for query_metric in self.query_metrics.iter() {
- for (ndcg, query_ndcg) in ndcg_sum.iter_mut().zip(query_metric.ndcg.clone()) {
- *ndcg += query_ndcg;
- }
-
- for (mapp, query_map) in map_sum.iter_mut().zip(query_metric.map.clone()) {
- *mapp += query_map;
- }
-
- for (pre, query_pre) in precision_sum.iter_mut().zip(query_metric.precision.clone()) {
- *pre += query_pre;
- }
-
- for (rec, query_rec) in recall_sum.iter_mut().zip(query_metric.recall.clone()) {
- *rec += query_rec;
- }
-
- mmr_sum += query_metric.mrr;
- }
-
- let ndcg = ndcg_sum.iter().map(|val| val / l).collect::<Vec<f32>>();
- let map = map_sum.iter().map(|val| val / l).collect::<Vec<f32>>();
- let precision = precision_sum
- .iter()
- .map(|val| val / l)
- .collect::<Vec<f32>>();
- let recall = recall_sum.iter().map(|val| val / l).collect::<Vec<f32>>();
- let mrr = mmr_sum / l;
-
- self.repo_metrics = Some(SummaryMetrics {
- millis_to_search,
- ndcg,
- map,
- mrr,
- precision,
- recall,
- })
- }
-}
-
-fn evaluate_precision(hits: Vec<usize>) -> Vec<f32> {
- let mut rolling_hit: f32 = 0.0;
- let mut precision = Vec::new();
- for (idx, hit) in hits.into_iter().enumerate() {
- rolling_hit += hit as f32;
- precision.push(rolling_hit / ((idx as f32) + 1.0));
- }
-
- precision
-}
-
-fn evaluate_recall(hits: Vec<usize>, ideal: Vec<usize>) -> Vec<f32> {
- let total_relevant = ideal.iter().sum::<usize>() as f32;
- let mut recall = Vec::new();
- let mut rolling_hit: f32 = 0.0;
- for hit in hits {
- rolling_hit += hit as f32;
- recall.push(rolling_hit / total_relevant);
- }
-
- recall
-}
-
-async fn evaluate_repo(
- repo_name: String,
- index: ModelHandle<SemanticIndex>,
- project: ModelHandle<Project>,
- query_matches: Vec<EvaluationQuery>,
- cx: &mut AsyncAppContext,
-) -> Result<RepoEvaluationMetrics> {
- // Index Project
- let index_t0 = Instant::now();
- index
- .update(cx, |index, cx| index.index_project(project.clone(), cx))
- .await?;
- let mut repo_metrics = RepoEvaluationMetrics::new(index_t0.elapsed());
-
- for query in query_matches {
- // Query each match in order
- let search_t0 = Instant::now();
- let search_results = index
- .update(cx, |index, cx| {
- index.search_project(project.clone(), query.clone().query, 10, vec![], vec![], cx)
- })
- .await?;
- let millis_to_search = search_t0.elapsed();
-
- // Get Hits/Ideal
- let k = 10;
- let (ideal, hits) = self::get_hits(query.clone(), search_results, k, cx);
-
- // Evaluate ndcg@k, for k = 1, 3, 5, 10
- let ndcg = evaluate_ndcg(hits.clone(), ideal.clone());
-
- // Evaluate map@k, for k = 1, 3, 5, 10
- let map = evaluate_map(hits.clone());
-
- // Evaluate mrr
- let mrr = evaluate_mrr(hits.clone());
-
- // Evaluate precision
- let precision = evaluate_precision(hits.clone());
-
- // Evaluate Recall
- let recall = evaluate_recall(hits.clone(), ideal);
-
- let query_metrics = QueryMetrics {
- query,
- millis_to_search,
- ndcg,
- map,
- mrr,
- hits,
- precision,
- recall,
- };
-
- repo_metrics.query_metrics.push(query_metrics);
- }
-
- repo_metrics.summarize();
- let _ = repo_metrics.save(repo_name);
-
- anyhow::Ok(repo_metrics)
-}
-
-fn main() {
- // Launch new repo as a new Zed workspace/project
- let app = gpui::App::new(()).unwrap();
- let fs = Arc::new(RealFs);
- let http = http::client();
- let http_client = http::client();
- init_logger();
-
- app.run(move |cx| {
- cx.set_global(*RELEASE_CHANNEL);
-
- let client = client::Client::new(http.clone(), cx);
- let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client.clone(), cx));
-
- // Initialize Settings
- let mut store = SettingsStore::default();
- store
- .set_default_settings(default_settings().as_ref(), cx)
- .unwrap();
- cx.set_global(store);
-
- // Initialize Languages
- let login_shell_env_loaded = Task::ready(());
- let mut languages = LanguageRegistry::new(login_shell_env_loaded);
- languages.set_executor(cx.background().clone());
- let languages = Arc::new(languages);
-
- let node_runtime = RealNodeRuntime::new(http.clone());
- languages::init(languages.clone(), node_runtime.clone(), cx);
- language::init(cx);
-
- project::Project::init(&client, cx);
- semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx);
-
- settings::register::<SemanticIndexSettings>(cx);
-
- let db_file_path = EMBEDDINGS_DIR
- .join(Path::new(RELEASE_CHANNEL_NAME.as_str()))
- .join("embeddings_db");
-
- let languages = languages.clone();
-
- let fs = fs.clone();
- cx.spawn(|mut cx| async move {
- let semantic_index = SemanticIndex::new(
- fs.clone(),
- db_file_path,
- Arc::new(OpenAIEmbeddingProvider::new(http_client, cx.background())),
- languages.clone(),
- cx.clone(),
- )
- .await?;
-
- if let Ok(repo_evals) = parse_eval() {
- for repo in repo_evals {
- let cloned = clone_repo(repo.clone());
- match cloned {
- Ok((repo_name, clone_path)) => {
- println!(
- "Cloned {:?} @ {:?} into {:?}",
- repo.repo, repo.commit, &clone_path
- );
-
- // Create Project
- let project = cx.update(|cx| {
- Project::local(
- client.clone(),
- node_runtime::FakeNodeRuntime::new(),
- user_store.clone(),
- languages.clone(),
- fs.clone(),
- cx,
- )
- });
-
- // Register Worktree
- let _ = project
- .update(&mut cx, |project, cx| {
- project.find_or_create_local_worktree(clone_path, true, cx)
- })
- .await;
-
- let _ = evaluate_repo(
- repo_name,
- semantic_index.clone(),
- project,
- repo.assertions,
- &mut cx,
- )
- .await?;
- }
- Err(err) => {
- println!("Error cloning: {:?}", err);
- }
- }
- }
- }
-
- anyhow::Ok(())
- })
- .detach();
- });
-}
@@ -1,5 +1,6 @@
-use anyhow::{anyhow, Result};
-use gpui::AssetSource;
+use anyhow::anyhow;
+
+use gpui::{AssetSource, Result, SharedString};
use rust_embed::RustEmbed;
#[derive(RustEmbed)]
@@ -7,6 +8,7 @@ use rust_embed::RustEmbed;
#[include = "fonts/**/*"]
#[include = "icons/**/*"]
#[include = "themes/**/*"]
+#[exclude = "themes/src/*"]
#[include = "sounds/**/*"]
#[include = "*.md"]
#[exclude = "*.DS_Store"]
@@ -19,7 +21,15 @@ impl AssetSource for Assets {
.ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
}
- fn list(&self, path: &str) -> Vec<std::borrow::Cow<'static, str>> {
- Self::iter().filter(|p| p.starts_with(path)).collect()
+ fn list(&self, path: &str) -> Result<Vec<SharedString>> {
+ Ok(Self::iter()
+ .filter_map(|p| {
+ if p.starts_with(path) {
+ Some(p.into())
+ } else {
+ None
+ }
+ })
+ .collect())
}
}
@@ -3,8 +3,9 @@ use gpui::AppContext;
pub use language::*;
use node_runtime::NodeRuntime;
use rust_embed::RustEmbed;
+use settings::Settings;
use std::{borrow::Cow, str, sync::Arc};
-use util::asset_str;
+use util::{asset_str, paths::PLUGINS_DIR};
use self::elixir::ElixirSettings;
@@ -48,7 +49,7 @@ pub fn init(
node_runtime: Arc<dyn NodeRuntime>,
cx: &mut AppContext,
) {
- settings::register::<elixir::ElixirSettings>(cx);
+ ElixirSettings::register(cx);
let language = |name, grammar, adapters| {
languages.register(name, load_config(name), grammar, adapters, load_queries)
@@ -74,7 +75,7 @@ pub fn init(
],
);
- match &settings::get::<ElixirSettings>(cx).lsp {
+ match &ElixirSettings::get(None, cx).lsp {
elixir::ElixirLspSetting::ElixirLs => language(
"elixir",
tree_sitter_elixir::language(),
@@ -227,6 +228,21 @@ pub fn init(
tree_sitter_uiua::language(),
vec![Arc::new(uiua::UiuaLanguageServer {})],
);
+
+ if let Ok(children) = std::fs::read_dir(&*PLUGINS_DIR) {
+ for child in children {
+ if let Ok(child) = child {
+ let path = child.path();
+ let config_path = path.join("config.toml");
+ if let Ok(config) = std::fs::read(&config_path) {
+ let config: LanguageConfig = toml::from_slice(&config).unwrap();
+ if let Some(grammar_name) = config.grammar_name.clone() {
+ languages.register_wasm(path.into(), grammar_name, config);
+ }
+ }
+ }
+ }
+ }
}
#[cfg(any(test, feature = "test-support"))]
@@ -273,18 +273,19 @@ async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServ
#[cfg(test)]
mod tests {
- use gpui::TestAppContext;
+ use gpui::{Context, TestAppContext};
use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer};
use settings::SettingsStore;
use std::num::NonZeroU32;
#[gpui::test]
async fn test_c_autoindent(cx: &mut TestAppContext) {
- cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX);
+ // cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX);
cx.update(|cx| {
- cx.set_global(SettingsStore::test(cx));
+ let test_settings = SettingsStore::test(cx);
+ cx.set_global(test_settings);
language::init(cx);
- cx.update_global::<SettingsStore, _, _>(|store, cx| {
+ cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<AllLanguageSettings>(cx, |s| {
s.defaults.tab_size = NonZeroU32::new(2);
});
@@ -292,8 +293,9 @@ mod tests {
});
let language = crate::languages::language("c", tree_sitter_c::language(), None).await;
- cx.add_model(|cx| {
- let mut buffer = Buffer::new(0, cx.model_id() as u64, "").with_language(language, cx);
+ cx.new_model(|cx| {
+ let mut buffer =
+ Buffer::new(0, cx.entity_id().as_u64(), "").with_language(language, cx);
// empty function
buffer.edit([(0..0, "int main() {}")], None, cx);
@@ -6,7 +6,7 @@ pub use language::*;
use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind};
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
-use settings::Setting;
+use settings::Settings;
use smol::fs::{self, File};
use std::{
any::Any,
@@ -46,7 +46,7 @@ pub struct ElixirSettingsContent {
lsp: Option<ElixirLspSetting>,
}
-impl Setting for ElixirSettings {
+impl Settings for ElixirSettings {
const KEY: Option<&'static str> = Some("elixir");
type FileContent = ElixirSettingsContent;
@@ -54,7 +54,7 @@ impl Setting for ElixirSettings {
fn load(
default_value: &Self::FileContent,
user_values: &[&Self::FileContent],
- _: &gpui::AppContext,
+ _: &mut gpui::AppContext,
) -> Result<Self>
where
Self: Sized,
@@ -85,7 +85,7 @@ impl LspAdapter for ElixirLspAdapter {
const NOTIFICATION_MESSAGE: &str = "Could not run the elixir language server, `elixir-ls`, because `elixir` was not found.";
let delegate = delegate.clone();
- Some(cx.spawn(|mut cx| async move {
+ Some(cx.spawn(|cx| async move {
let elixir_output = smol::process::Command::new("elixir")
.args(["--version"])
.output()
@@ -97,7 +97,7 @@ impl LspAdapter for ElixirLspAdapter {
{
cx.update(|cx| {
delegate.show_notification(NOTIFICATION_MESSAGE, cx);
- })
+ })?
}
return Err(anyhow!("cannot run elixir-ls"));
}
@@ -18,10 +18,10 @@
target: (identifier) @name)
operator: "when")
])
- (#any-match? @name "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
+ (#match? @name "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
)
(call
target: (identifier) @name
(arguments (alias) @name)
- (#any-match? @name "^(defmodule|defprotocol)$")) @item
+ (#match? @name "^(defmodule|defprotocol)$")) @item
@@ -67,7 +67,7 @@ impl super::LspAdapter for GoLspAdapter {
"Could not install the Go language server `gopls`, because `go` was not found.";
let delegate = delegate.clone();
- Some(cx.spawn(|mut cx| async move {
+ Some(cx.spawn(|cx| async move {
let install_output = process::Command::new("go").args(["version"]).output().await;
if install_output.is_err() {
if DID_SHOW_NOTIFICATION
@@ -76,7 +76,7 @@ impl super::LspAdapter for GoLspAdapter {
{
cx.update(|cx| {
delegate.show_notification(NOTIFICATION_MESSAGE, cx);
- })
+ })?
}
return Err(anyhow!("cannot install gopls"));
}
@@ -372,7 +372,7 @@ fn adjust_runs(
mod tests {
use super::*;
use crate::languages::language;
- use gpui::color::Color;
+ use gpui::Hsla;
use theme::SyntaxTheme;
#[gpui::test]
@@ -384,12 +384,12 @@ mod tests {
)
.await;
- let theme = SyntaxTheme::new(vec![
- ("type".into(), Color::green().into()),
- ("keyword".into(), Color::blue().into()),
- ("function".into(), Color::red().into()),
- ("number".into(), Color::yellow().into()),
- ("property".into(), Color::white().into()),
+ let theme = SyntaxTheme::new_test([
+ ("type", Hsla::default()),
+ ("keyword", Hsla::default()),
+ ("function", Hsla::default()),
+ ("number", Hsla::default()),
+ ("property", Hsla::default()),
]);
language.set_theme(&theme);
@@ -108,7 +108,7 @@ impl LspAdapter for JsonLspAdapter {
_workspace_root: &Path,
cx: &mut AppContext,
) -> BoxFuture<'static, serde_json::Value> {
- let action_names = cx.all_action_names().collect::<Vec<_>>();
+ let action_names = cx.all_action_names();
let staff_mode = cx.is_staff();
let language_names = &self.languages.language_names();
let settings_schema = cx.global::<SettingsStore>().json_schema(
@@ -3,8 +3,8 @@ use async_trait::async_trait;
use collections::HashMap;
use futures::lock::Mutex;
use gpui::executor::Background;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
+use language2::{LanguageServerName, LspAdapter, LspAdapterDelegate};
+use lsp2::LanguageServerBinary;
use plugin_runtime::{Plugin, PluginBinary, PluginBuilder, WasiFn};
use std::{any::Any, path::PathBuf, sync::Arc};
use util::ResultExt;
@@ -1,8 +1,8 @@
use anyhow::{anyhow, Result};
use async_trait::async_trait;
-use language::{CodeLabel, Language, LanguageServerName, LspAdapter, LspAdapterDelegate};
+use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary;
-use std::{any::Any, path::PathBuf, sync::Arc};
+use std::{any::Any, path::PathBuf};
pub struct NuLanguageServer;
@@ -52,30 +52,4 @@ impl LspAdapter for NuLanguageServer {
async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
None
}
-
- async fn label_for_completion(
- &self,
- completion: &lsp::CompletionItem,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- return Some(CodeLabel {
- runs: language
- .highlight_text(&completion.label.clone().into(), 0..completion.label.len()),
- text: completion.label.clone(),
- filter_range: 0..completion.label.len(),
- });
- }
-
- async fn label_for_symbol(
- &self,
- name: &str,
- _: lsp::SymbolKind,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- Some(CodeLabel {
- runs: language.highlight_text(&name.into(), 0..name.len()),
- text: name.to_string(),
- filter_range: 0..name.len(),
- })
- }
}
@@ -177,28 +177,30 @@ async fn get_cached_server_binary(
#[cfg(test)]
mod tests {
- use gpui::{ModelContext, TestAppContext};
+ use gpui::{Context, ModelContext, TestAppContext};
use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer};
use settings::SettingsStore;
use std::num::NonZeroU32;
#[gpui::test]
async fn test_python_autoindent(cx: &mut TestAppContext) {
- cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX);
+ // cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX);
let language =
crate::languages::language("python", tree_sitter_python::language(), None).await;
cx.update(|cx| {
- cx.set_global(SettingsStore::test(cx));
+ let test_settings = SettingsStore::test(cx);
+ cx.set_global(test_settings);
language::init(cx);
- cx.update_global::<SettingsStore, _, _>(|store, cx| {
+ cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<AllLanguageSettings>(cx, |s| {
s.defaults.tab_size = NonZeroU32::new(2);
});
});
});
- cx.add_model(|cx| {
- let mut buffer = Buffer::new(0, cx.model_id() as u64, "").with_language(language, cx);
+ cx.new_model(|cx| {
+ let mut buffer =
+ Buffer::new(0, cx.entity_id().as_u64(), "").with_language(language, cx);
let append = |buffer: &mut Buffer, text: &str, cx: &mut ModelContext<Buffer>| {
let ix = buffer.len();
buffer.edit([(ix..ix, text)], Some(AutoindentMode::EachLine), cx);
@@ -294,7 +294,7 @@ mod tests {
use super::*;
use crate::languages::language;
- use gpui::{color::Color, TestAppContext};
+ use gpui::{Context, Hsla, TestAppContext};
use language::language_settings::AllLanguageSettings;
use settings::SettingsStore;
use theme::SyntaxTheme;
@@ -349,11 +349,11 @@ mod tests {
)
.await;
let grammar = language.grammar().unwrap();
- let theme = SyntaxTheme::new(vec![
- ("type".into(), Color::green().into()),
- ("keyword".into(), Color::blue().into()),
- ("function".into(), Color::red().into()),
- ("property".into(), Color::white().into()),
+ let theme = SyntaxTheme::new_test([
+ ("type", Hsla::default()),
+ ("keyword", Hsla::default()),
+ ("function", Hsla::default()),
+ ("property", Hsla::default()),
]);
language.set_theme(&theme);
@@ -456,11 +456,11 @@ mod tests {
)
.await;
let grammar = language.grammar().unwrap();
- let theme = SyntaxTheme::new(vec![
- ("type".into(), Color::green().into()),
- ("keyword".into(), Color::blue().into()),
- ("function".into(), Color::red().into()),
- ("property".into(), Color::white().into()),
+ let theme = SyntaxTheme::new_test([
+ ("type", Hsla::default()),
+ ("keyword", Hsla::default()),
+ ("function", Hsla::default()),
+ ("property", Hsla::default()),
]);
language.set_theme(&theme);
@@ -494,11 +494,12 @@ mod tests {
#[gpui::test]
async fn test_rust_autoindent(cx: &mut TestAppContext) {
- cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX);
+ // cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX);
cx.update(|cx| {
- cx.set_global(SettingsStore::test(cx));
+ let test_settings = SettingsStore::test(cx);
+ cx.set_global(test_settings);
language::init(cx);
- cx.update_global::<SettingsStore, _, _>(|store, cx| {
+ cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<AllLanguageSettings>(cx, |s| {
s.defaults.tab_size = NonZeroU32::new(2);
});
@@ -507,8 +508,9 @@ mod tests {
let language = crate::languages::language("rust", tree_sitter_rust::language(), None).await;
- cx.add_model(|cx| {
- let mut buffer = Buffer::new(0, cx.model_id() as u64, "").with_language(language, cx);
+ cx.new_model(|cx| {
+ let mut buffer =
+ Buffer::new(0, cx.entity_id().as_u64(), "").with_language(language, cx);
// indent between braces
buffer.set_text("fn a() {}", cx);
@@ -351,7 +351,7 @@ async fn get_cached_eslint_server_binary(
#[cfg(test)]
mod tests {
- use gpui::TestAppContext;
+ use gpui::{Context, TestAppContext};
use unindent::Unindent;
#[gpui::test]
@@ -378,10 +378,10 @@ mod tests {
"#
.unindent();
- let buffer = cx.add_model(|cx| {
- language::Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx)
+ let buffer = cx.new_model(|cx| {
+ language::Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx)
});
- let outline = buffer.read_with(cx, |buffer, _| buffer.snapshot().outline(None).unwrap());
+ let outline = buffer.update(cx, |buffer, _| buffer.snapshot().outline(None).unwrap());
assert_eq!(
outline
.items
@@ -3,7 +3,7 @@ path_suffixes = ["ua"]
line_comment = "# "
autoclose_before = ")]}\""
brackets = [
- { start = "{", end = "}", close = true, newline = false },
+ { start = "{", end = "}", close = true, newline = false},
{ start = "[", end = "]", close = true, newline = false },
{ start = "(", end = ")", close = true, newline = false },
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
@@ -1,59 +1,62 @@
// Allow binary to be called Zed for a nice application menu when running executable directly
#![allow(non_snake_case)]
-use anyhow::{anyhow, Context, Result};
+use anyhow::{anyhow, Context as _, Result};
use backtrace::Backtrace;
use chrono::Utc;
use cli::FORCE_CLI_MODE_ENV_VAR_NAME;
-use client::{
- self, Client, TelemetrySettings, UserStore, ZED_APP_VERSION, ZED_SECRET_CLIENT_TOKEN,
-};
+use client::{Client, UserStore};
use collab_ui::channel_view::ChannelView;
use db::kvp::KEY_VALUE_STORE;
use editor::Editor;
+use fs::RealFs;
use futures::StreamExt;
-use gpui::{Action, App, AppContext, AssetSource, AsyncAppContext, Task};
-use isahc::{config::Configurable, Request};
+use gpui::{App, AppContext, AsyncAppContext, Context, SemanticVersion, Task};
+use isahc::{prelude::Configurable, Request};
use language::LanguageRegistry;
use log::LevelFilter;
+
use node_runtime::RealNodeRuntime;
use parking_lot::Mutex;
-use project::Fs;
use serde::{Deserialize, Serialize};
-use settings::{default_settings, handle_settings_file_changes, watch_config_file, SettingsStore};
+use settings::{
+ default_settings, handle_settings_file_changes, watch_config_file, Settings, SettingsStore,
+};
use simplelog::ConfigBuilder;
use smol::process::Command;
use std::{
env,
ffi::OsStr,
fs::OpenOptions,
- io::{IsTerminal, Write as _},
+ io::{IsTerminal, Write},
panic,
- path::Path,
+ path::{Path, PathBuf},
sync::{
atomic::{AtomicU32, Ordering},
Arc, Weak,
},
thread,
};
+use theme::ActiveTheme;
use util::{
- channel::{parse_zed_link, ReleaseChannel},
+ async_maybe,
+ channel::{parse_zed_link, AppCommitSha, ReleaseChannel, RELEASE_CHANNEL},
http::{self, HttpClient},
+ paths, ResultExt,
};
use uuid::Uuid;
-use welcome::{show_welcome_experience, FIRST_OPEN};
-
-use fs::RealFs;
-use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt};
+use welcome::{show_welcome_view, FIRST_OPEN};
use workspace::{AppState, WorkspaceStore};
use zed::{
- assets::Assets,
- build_window_options, handle_keymap_file_changes, initialize_workspace, languages, menus,
- only_instance::{ensure_only_instance, IsOnlyInstance},
- open_listener::{handle_cli_connection, OpenListener, OpenRequest},
+ app_menus, build_window_options, ensure_only_instance, handle_cli_connection,
+ handle_keymap_file_changes, initialize_workspace, languages, Assets, IsOnlyInstance,
+ OpenListener, OpenRequest,
};
fn main() {
+ menu::init();
+ zed_actions::init();
+
let http = http::client();
init_paths();
init_logger();
@@ -63,48 +66,61 @@ fn main() {
}
log::info!("========== starting zed ==========");
- let mut app = gpui::App::new(Assets).unwrap();
+ let app = App::production(Arc::new(Assets));
- let (installation_id, existing_installation_id_found) =
- app.background().block(installation_id()).ok().unzip();
+ let (installation_id, existing_installation_id_found) = app
+ .background_executor()
+ .block(installation_id())
+ .ok()
+ .unzip();
let session_id = Uuid::new_v4().to_string();
init_panic_hook(&app, installation_id.clone(), session_id.clone());
- load_embedded_fonts(&app);
-
let fs = Arc::new(RealFs);
- let user_settings_file_rx =
- watch_config_file(app.background(), fs.clone(), paths::SETTINGS.clone());
- let user_keymap_file_rx =
- watch_config_file(app.background(), fs.clone(), paths::KEYMAP.clone());
+ let user_settings_file_rx = watch_config_file(
+ &app.background_executor(),
+ fs.clone(),
+ paths::SETTINGS.clone(),
+ );
+ let user_keymap_file_rx = watch_config_file(
+ &app.background_executor(),
+ fs.clone(),
+ paths::KEYMAP.clone(),
+ );
let login_shell_env_loaded = if stdout_is_a_pty() {
Task::ready(())
} else {
- app.background().spawn(async {
+ app.background_executor().spawn(async {
load_login_shell_environment().await.log_err();
})
};
let (listener, mut open_rx) = OpenListener::new();
let listener = Arc::new(listener);
- let callback_listener = listener.clone();
- app.on_open_urls(move |urls, _| callback_listener.open_urls(urls))
- .on_reopen(move |cx| {
- if cx.has_global::<Weak<AppState>>() {
- if let Some(app_state) = cx.global::<Weak<AppState>>().upgrade() {
- workspace::open_new(&app_state, cx, |workspace, cx| {
- Editor::new_file(workspace, &Default::default(), cx)
- })
- .detach();
- }
+ let open_listener = listener.clone();
+ app.on_open_urls(move |urls, _| open_listener.open_urls(&urls));
+ app.on_reopen(move |cx| {
+ if cx.has_global::<Weak<AppState>>() {
+ if let Some(app_state) = cx.global::<Weak<AppState>>().upgrade() {
+ workspace::open_new(&app_state, cx, |workspace, cx| {
+ Editor::new_file(workspace, &Default::default(), cx)
+ })
+ .detach();
}
- });
+ }
+ });
app.run(move |cx| {
cx.set_global(*RELEASE_CHANNEL);
+ if let Some(build_sha) = option_env!("ZED_COMMIT_SHA") {
+ cx.set_global(AppCommitSha(build_sha.into()))
+ }
+
cx.set_global(listener.clone());
+ load_embedded_fonts(cx);
+
let mut store = SettingsStore::default();
store
.set_default_settings(default_settings().as_ref(), cx)
@@ -116,35 +132,25 @@ fn main() {
let client = client::Client::new(http.clone(), cx);
let mut languages = LanguageRegistry::new(login_shell_env_loaded);
let copilot_language_server_id = languages.next_language_server_id();
- languages.set_executor(cx.background().clone());
+ languages.set_executor(cx.background_executor().clone());
languages.set_language_server_download_dir(paths::LANGUAGES_DIR.clone());
let languages = Arc::new(languages);
let node_runtime = RealNodeRuntime::new(http.clone());
+ language::init(cx);
languages::init(languages.clone(), node_runtime.clone(), cx);
- let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx));
- let workspace_store = cx.add_model(|cx| WorkspaceStore::new(client.clone(), cx));
+ let user_store = cx.new_model(|cx| UserStore::new(client.clone(), cx));
+ let workspace_store = cx.new_model(|cx| WorkspaceStore::new(client.clone(), cx));
cx.set_global(client.clone());
- theme::init(Assets, cx);
- context_menu::init(cx);
+ theme::init(theme::LoadThemes::All, cx);
project::Project::init(&client, cx);
client::init(&client, cx);
command_palette::init(cx);
language::init(cx);
editor::init(cx);
- go_to_line::init(cx);
- file_finder::init(cx);
- outline::init(cx);
- project_symbols::init(cx);
- project_panel::init(Assets, cx);
- channel::init(&client, user_store.clone(), cx);
diagnostics::init(cx);
- search::init(cx);
- semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx);
- vim::init(cx);
- terminal_view::init(cx);
copilot::init(
copilot_language_server_id,
http.clone(),
@@ -152,26 +158,25 @@ fn main() {
cx,
);
assistant::init(cx);
- component_test::init(cx);
+ // component_test::init(cx);
- cx.spawn(|cx| watch_themes(fs.clone(), cx)).detach();
cx.spawn(|_| watch_languages(fs.clone(), languages.clone()))
.detach();
watch_file_types(fs.clone(), cx);
- languages.set_theme(theme::current(cx).clone());
- cx.observe_global::<SettingsStore, _>({
+ languages.set_theme(cx.theme().clone());
+ cx.observe_global::<SettingsStore>({
let languages = languages.clone();
- move |cx| languages.set_theme(theme::current(cx).clone())
+ move |cx| languages.set_theme(cx.theme().clone())
})
.detach();
client.telemetry().start(installation_id, session_id, cx);
- let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
+ let telemetry_settings = *client::TelemetrySettings::get_global(cx);
client.telemetry().report_setting_event(
telemetry_settings,
"theme",
- theme::current(cx).meta.name.to_string(),
+ cx.theme().name.to_string(),
);
let event_operation = match existing_installation_id_found {
Some(false) => "first open",
@@ -182,13 +187,11 @@ fn main() {
.report_app_event(telemetry_settings, event_operation, true);
let app_state = Arc::new(AppState {
- languages,
+ languages: languages.clone(),
client: client.clone(),
- user_store,
- fs,
+ user_store: user_store.clone(),
+ fs: fs.clone(),
build_window_options,
- initialize_workspace,
- background_actions,
workspace_store,
node_runtime,
});
@@ -200,25 +203,35 @@ fn main() {
workspace::init(app_state.clone(), cx);
recent_projects::init(cx);
+ go_to_line::init(cx);
+ file_finder::init(cx);
+ outline::init(cx);
+ project_symbols::init(cx);
+ project_panel::init(Assets, cx);
+ channel::init(&client, user_store.clone(), cx);
+ search::init(cx);
+ semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx);
+ vim::init(cx);
+ terminal_view::init(cx);
+
journal::init(app_state.clone(), cx);
language_selector::init(cx);
theme_selector::init(cx);
- activity_indicator::init(cx);
language_tools::init(cx);
call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
notifications::init(app_state.client.clone(), app_state.user_store.clone(), cx);
collab_ui::init(&app_state, cx);
feedback::init(cx);
welcome::init(cx);
- zed::init(&app_state, cx);
- cx.set_menus(menus::menus());
+ cx.set_menus(app_menus());
+ initialize_workspace(app_state.clone(), cx);
if stdout_is_a_pty() {
- cx.platform().activate(true);
+ cx.activate(true);
let urls = collect_url_args();
if !urls.is_empty() {
- listener.open_urls(urls)
+ listener.open_urls(&urls)
}
} else {
upload_previous_panics(http.clone(), cx);
@@ -228,32 +241,51 @@ fn main() {
if std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_some()
&& !listener.triggered.load(Ordering::Acquire)
{
- listener.open_urls(collect_url_args())
+ listener.open_urls(&collect_url_args())
}
}
let mut triggered_authentication = false;
+ fn open_paths_and_log_errs(
+ paths: &[PathBuf],
+ app_state: &Arc<AppState>,
+ cx: &mut AppContext,
+ ) {
+ let task = workspace::open_paths(&paths, &app_state, None, cx);
+ cx.spawn(|_| async move {
+ if let Some((_window, results)) = task.await.log_err() {
+ for result in results {
+ if let Some(Err(e)) = result {
+ log::error!("Error opening path: {}", e);
+ }
+ }
+ }
+ })
+ .detach();
+ }
+
match open_rx.try_next() {
Ok(Some(OpenRequest::Paths { paths })) => {
- cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx))
- .detach();
+ open_paths_and_log_errs(&paths, &app_state, cx)
}
Ok(Some(OpenRequest::CliConnection { connection })) => {
- cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx))
+ let app_state = app_state.clone();
+ cx.spawn(move |cx| handle_cli_connection(connection, app_state, cx))
.detach();
}
Ok(Some(OpenRequest::JoinChannel { channel_id })) => {
triggered_authentication = true;
let app_state = app_state.clone();
let client = client.clone();
- cx.spawn(|mut cx| async move {
+ cx.spawn(|cx| async move {
// ignore errors here, we'll show a generic "not signed in"
let _ = authenticate(client, &cx).await;
- cx.update(|cx| workspace::join_channel(channel_id, app_state, None, cx))
- .await
+ cx.update(|cx| workspace::join_channel(channel_id, app_state, None, cx))?
+ .await?;
+ anyhow::Ok(())
})
- .detach_and_log_err(cx)
+ .detach_and_log_err(cx);
}
Ok(Some(OpenRequest::OpenChannelNotes { channel_id })) => {
triggered_authentication = true;
@@ -262,12 +294,16 @@ fn main() {
cx.spawn(|mut cx| async move {
// ignore errors here, we'll show a generic "not signed in"
let _ = authenticate(client, &cx).await;
- let workspace =
+ let workspace_window =
workspace::get_any_active_workspace(app_state, cx.clone()).await?;
- cx.update(|cx| ChannelView::open(channel_id, workspace, cx))
- .await
+ let _ = workspace_window
+ .update(&mut cx, |_, cx| {
+ ChannelView::open(channel_id, cx.view().clone(), cx)
+ })?
+ .await?;
+ anyhow::Ok(())
})
- .detach_and_log_err(cx)
+ .detach_and_log_err(cx);
}
Ok(None) | Err(_) => cx
.spawn({
@@ -277,36 +313,49 @@ fn main() {
.detach(),
}
- cx.spawn(|mut cx| {
- let app_state = app_state.clone();
- async move {
- while let Some(request) = open_rx.next().await {
- match request {
- OpenRequest::Paths { paths } => {
- cx.update(|cx| {
- workspace::open_paths(&paths, &app_state.clone(), None, cx)
- })
- .detach();
- }
- OpenRequest::CliConnection { connection } => {
- cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx))
- .detach();
- }
- OpenRequest::JoinChannel { channel_id } => cx
- .update(|cx| {
- workspace::join_channel(channel_id, app_state.clone(), None, cx)
- })
- .detach(),
- OpenRequest::OpenChannelNotes { channel_id } => {
- let app_state = app_state.clone();
- if let Ok(workspace) =
- workspace::get_any_active_workspace(app_state, cx.clone()).await
- {
+ let app_state = app_state.clone();
+ cx.spawn(move |cx| async move {
+ while let Some(request) = open_rx.next().await {
+ match request {
+ OpenRequest::Paths { paths } => {
+ cx.update(|cx| open_paths_and_log_errs(&paths, &app_state, cx))
+ .ok();
+ }
+ OpenRequest::CliConnection { connection } => {
+ let app_state = app_state.clone();
+ cx.spawn(move |cx| {
+ handle_cli_connection(connection, app_state.clone(), cx)
+ })
+ .detach();
+ }
+ OpenRequest::JoinChannel { channel_id } => {
+ let app_state = app_state.clone();
+ cx.update(|mut cx| {
+ cx.spawn(|cx| async move {
cx.update(|cx| {
- ChannelView::open(channel_id, workspace, cx).detach();
- })
- }
- }
+ workspace::join_channel(channel_id, app_state, None, cx)
+ })?
+ .await?;
+ anyhow::Ok(())
+ })
+ .detach_and_log_err(&mut cx);
+ })
+ .log_err();
+ }
+ OpenRequest::OpenChannelNotes { channel_id } => {
+ let app_state = app_state.clone();
+ let open_notes_task = cx.spawn(|mut cx| async move {
+ let workspace_window =
+ workspace::get_any_active_workspace(app_state, cx.clone()).await?;
+ let _ = workspace_window
+ .update(&mut cx, |_, cx| {
+ ChannelView::open(channel_id, cx.view().clone(), cx)
+ })?
+ .await?;
+ anyhow::Ok(())
+ });
+ cx.update(|cx| open_notes_task.detach_and_log_err(cx))
+ .log_err();
}
}
}
@@ -357,21 +406,26 @@ async fn installation_id() -> Result<(String, bool)> {
Ok((installation_id, false))
}
-async fn restore_or_create_workspace(app_state: &Arc<AppState>, mut cx: AsyncAppContext) {
- if let Some(location) = workspace::last_opened_workspace_paths().await {
- cx.update(|cx| workspace::open_paths(location.paths().as_ref(), app_state, None, cx))
- .await
- .log_err();
- } else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) {
- cx.update(|cx| show_welcome_experience(app_state, cx));
- } else {
- cx.update(|cx| {
- workspace::open_new(app_state, cx, |workspace, cx| {
- Editor::new_file(workspace, &Default::default(), cx)
- })
- .detach();
- });
- }
+async fn restore_or_create_workspace(app_state: &Arc<AppState>, cx: AsyncAppContext) {
+ async_maybe!({
+ if let Some(location) = workspace::last_opened_workspace_paths().await {
+ cx.update(|cx| workspace::open_paths(location.paths().as_ref(), app_state, None, cx))?
+ .await
+ .log_err();
+ } else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) {
+ cx.update(|cx| show_welcome_view(app_state, cx)).log_err();
+ } else {
+ cx.update(|cx| {
+ workspace::open_new(app_state, cx, |workspace, cx| {
+ Editor::new_file(workspace, &Default::default(), cx)
+ })
+ .detach();
+ })?;
+ }
+ anyhow::Ok(())
+ })
+ .await
+ .log_err();
}
fn init_paths() {
@@ -444,7 +498,7 @@ static PANIC_COUNT: AtomicU32 = AtomicU32::new(0);
fn init_panic_hook(app: &App, installation_id: Option<String>, session_id: String) {
let is_pty = stdout_is_a_pty();
- let platform = app.platform();
+ let app_metadata = app.metadata();
panic::set_hook(Box::new(move |info| {
let prior_panic_count = PANIC_COUNT.fetch_add(1, Ordering::SeqCst);
@@ -480,8 +534,8 @@ fn init_panic_hook(app: &App, installation_id: Option<String>, session_id: Strin
std::process::exit(-1);
}
- let app_version = ZED_APP_VERSION
- .or_else(|| platform.app_version().ok())
+ let app_version = client::ZED_APP_VERSION
+ .or(app_metadata.app_version)
.map_or("dev".to_string(), |v| v.to_string());
let backtrace = Backtrace::new();
@@ -508,11 +562,11 @@ fn init_panic_hook(app: &App, installation_id: Option<String>, session_id: Strin
}),
app_version: app_version.clone(),
release_channel: RELEASE_CHANNEL.display_name().into(),
- os_name: platform.os_name().into(),
- os_version: platform
- .os_version()
- .ok()
- .map(|os_version| os_version.to_string()),
+ os_name: app_metadata.os_name.into(),
+ os_version: app_metadata
+ .os_version
+ .as_ref()
+ .map(SemanticVersion::to_string),
architecture: env::consts::ARCH.into(),
panicked_on: Utc::now().timestamp_millis(),
backtrace,
@@ -545,83 +599,76 @@ fn init_panic_hook(app: &App, installation_id: Option<String>, session_id: Strin
}
fn upload_previous_panics(http: Arc<dyn HttpClient>, cx: &mut AppContext) {
- let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
-
- cx.background()
- .spawn({
- async move {
- let panic_report_url = format!("{}/api/panic", &*client::ZED_SERVER_URL);
- let mut children = smol::fs::read_dir(&*paths::LOGS_DIR).await?;
- while let Some(child) = children.next().await {
- let child = child?;
- let child_path = child.path();
-
- if child_path.extension() != Some(OsStr::new("panic")) {
- continue;
- }
- let filename = if let Some(filename) = child_path.file_name() {
- filename.to_string_lossy()
- } else {
- continue;
- };
-
- if !filename.starts_with("zed") {
- continue;
- }
+ let telemetry_settings = *client::TelemetrySettings::get_global(cx);
+
+ cx.background_executor()
+ .spawn(async move {
+ let panic_report_url = format!("{}/api/panic", &*client::ZED_SERVER_URL);
+ let mut children = smol::fs::read_dir(&*paths::LOGS_DIR).await?;
+ while let Some(child) = children.next().await {
+ let child = child?;
+ let child_path = child.path();
+
+ if child_path.extension() != Some(OsStr::new("panic")) {
+ continue;
+ }
+ let filename = if let Some(filename) = child_path.file_name() {
+ filename.to_string_lossy()
+ } else {
+ continue;
+ };
- if telemetry_settings.diagnostics {
- let panic_file_content = smol::fs::read_to_string(&child_path)
- .await
- .context("error reading panic file")?;
+ if !filename.starts_with("zed") {
+ continue;
+ }
- let panic = serde_json::from_str(&panic_file_content)
- .ok()
- .or_else(|| {
+ if telemetry_settings.diagnostics {
+ let panic_file_content = smol::fs::read_to_string(&child_path)
+ .await
+ .context("error reading panic file")?;
+
+ let panic = serde_json::from_str(&panic_file_content)
+ .ok()
+ .or_else(|| {
+ panic_file_content
+ .lines()
+ .next()
+ .and_then(|line| serde_json::from_str(line).ok())
+ })
+ .unwrap_or_else(|| {
+ log::error!(
+ "failed to deserialize panic file {:?}",
panic_file_content
- .lines()
- .next()
- .and_then(|line| serde_json::from_str(line).ok())
- })
- .unwrap_or_else(|| {
- log::error!(
- "failed to deserialize panic file {:?}",
- panic_file_content
- );
- None
- });
-
- if let Some(panic) = panic {
- let body = serde_json::to_string(&PanicRequest {
- panic,
- token: ZED_SECRET_CLIENT_TOKEN.into(),
- })
- .unwrap();
-
- let request = Request::post(&panic_report_url)
- .redirect_policy(isahc::config::RedirectPolicy::Follow)
- .header("Content-Type", "application/json")
- .body(body.into())?;
- let response =
- http.send(request).await.context("error sending panic")?;
- if !response.status().is_success() {
- log::error!(
- "Error uploading panic to server: {}",
- response.status()
- );
- }
+ );
+ None
+ });
+
+ if let Some(panic) = panic {
+ let body = serde_json::to_string(&PanicRequest {
+ panic,
+ token: client::ZED_SECRET_CLIENT_TOKEN.into(),
+ })
+ .unwrap();
+
+ let request = Request::post(&panic_report_url)
+ .redirect_policy(isahc::config::RedirectPolicy::Follow)
+ .header("Content-Type", "application/json")
+ .body(body.into())?;
+ let response = http.send(request).await.context("error sending panic")?;
+ if !response.status().is_success() {
+ log::error!("Error uploading panic to server: {}", response.status());
}
}
-
- // We've done what we can, delete the file
- std::fs::remove_file(child_path)
- .context("error removing panic")
- .log_err();
}
- Ok::<_, anyhow::Error>(())
+
+ // We've done what we can, delete the file
+ std::fs::remove_file(child_path)
+ .context("error removing panic")
+ .log_err();
}
- .log_err()
+ Ok::<_, anyhow::Error>(())
})
- .detach();
+ .detach_and_log_err(cx);
}
async fn load_login_shell_environment() -> Result<()> {
@@ -680,58 +727,38 @@ fn collect_url_args() -> Vec<String> {
.collect()
}
-fn load_embedded_fonts(app: &App) {
- let font_paths = Assets.list("fonts");
+fn load_embedded_fonts(cx: &AppContext) {
+ let asset_source = cx.asset_source();
+ let font_paths = asset_source.list("fonts").unwrap();
let embedded_fonts = Mutex::new(Vec::new());
- smol::block_on(app.background().scoped(|scope| {
+ let executor = cx.background_executor();
+
+ executor.block(executor.scoped(|scope| {
for font_path in &font_paths {
if !font_path.ends_with(".ttf") {
continue;
}
scope.spawn(async {
- let font_path = &*font_path;
- let font_bytes = Assets.load(font_path).unwrap().to_vec();
+ let font_bytes = asset_source.load(font_path).unwrap().to_vec();
embedded_fonts.lock().push(Arc::from(font_bytes));
});
}
}));
- app.platform()
- .fonts()
+
+ cx.text_system()
.add_fonts(&embedded_fonts.into_inner())
.unwrap();
}
#[cfg(debug_assertions)]
-async fn watch_themes(fs: Arc<dyn Fs>, mut cx: AsyncAppContext) -> Option<()> {
- let mut events = fs
- .watch("styles/src".as_ref(), std::time::Duration::from_millis(100))
- .await;
- while (events.next().await).is_some() {
- let output = Command::new("npm")
- .current_dir("styles")
- .args(["run", "build"])
- .output()
- .await
- .log_err()?;
- if output.status.success() {
- cx.update(|cx| theme_selector::reload(cx))
- } else {
- eprintln!(
- "build script failed {}",
- String::from_utf8_lossy(&output.stderr)
- );
- }
- }
- Some(())
-}
+async fn watch_languages(fs: Arc<dyn fs::Fs>, languages: Arc<LanguageRegistry>) -> Option<()> {
+ use std::time::Duration;
-#[cfg(debug_assertions)]
-async fn watch_languages(fs: Arc<dyn Fs>, languages: Arc<LanguageRegistry>) -> Option<()> {
let mut events = fs
.watch(
- "crates/zed/src/languages".as_ref(),
- std::time::Duration::from_millis(100),
+ "crates/zed2/src/languages".as_ref(),
+ Duration::from_millis(100),
)
.await;
while (events.next().await).is_some() {
@@ -741,12 +768,14 @@ async fn watch_languages(fs: Arc<dyn Fs>, languages: Arc<LanguageRegistry>) -> O
}
#[cfg(debug_assertions)]
-fn watch_file_types(fs: Arc<dyn Fs>, cx: &mut AppContext) {
- cx.spawn(|mut cx| async move {
+fn watch_file_types(fs: Arc<dyn fs::Fs>, cx: &mut AppContext) {
+ use std::time::Duration;
+
+ cx.spawn(|cx| async move {
let mut events = fs
.watch(
"assets/icons/file_icons/file_types.json".as_ref(),
- std::time::Duration::from_millis(100),
+ Duration::from_millis(100),
)
.await;
while (events.next().await).is_some() {
@@ -755,29 +784,16 @@ fn watch_file_types(fs: Arc<dyn Fs>, cx: &mut AppContext) {
*file_types = project_panel::file_associations::FileAssociations::new(Assets);
});
})
+ .ok();
}
})
.detach()
}
#[cfg(not(debug_assertions))]
-async fn watch_themes(_fs: Arc<dyn Fs>, _cx: AsyncAppContext) -> Option<()> {
- None
-}
-
-#[cfg(not(debug_assertions))]
-async fn watch_languages(_: Arc<dyn Fs>, _: Arc<LanguageRegistry>) -> Option<()> {
+async fn watch_languages(_: Arc<dyn fs::Fs>, _: Arc<LanguageRegistry>) -> Option<()> {
None
}
#[cfg(not(debug_assertions))]
-fn watch_file_types(_fs: Arc<dyn Fs>, _cx: &mut AppContext) {}
-
-pub fn background_actions() -> &'static [(&'static str, &'static dyn Action)] {
- &[
- ("Go to file", &file_finder::Toggle),
- ("Open command palette", &command_palette::Toggle),
- ("Open recent projects", &recent_projects::OpenRecent),
- ("Change your settings", &zed_actions::OpenSettings),
- ]
-}
+fn watch_file_types(_fs: Arc<dyn fs::Fs>, _cx: &mut AppContext) {}
@@ -1,174 +0,0 @@
-use gpui::{Menu, MenuItem, OsAction};
-
-#[cfg(target_os = "macos")]
-pub fn menus() -> Vec<Menu<'static>> {
- vec![
- Menu {
- name: "Zed",
- items: vec![
- MenuItem::action("About Zed…", super::About),
- MenuItem::action("Check for Updates", auto_update::Check),
- MenuItem::separator(),
- MenuItem::submenu(Menu {
- name: "Preferences",
- items: vec![
- MenuItem::action("Open Settings", super::OpenSettings),
- MenuItem::action("Open Key Bindings", super::OpenKeymap),
- MenuItem::action("Open Default Settings", super::OpenDefaultSettings),
- MenuItem::action("Open Default Key Bindings", super::OpenDefaultKeymap),
- MenuItem::action("Open Local Settings", super::OpenLocalSettings),
- MenuItem::action("Select Theme", theme_selector::Toggle),
- ],
- }),
- MenuItem::action("Install CLI", install_cli::Install),
- MenuItem::separator(),
- MenuItem::action("Hide Zed", super::Hide),
- MenuItem::action("Hide Others", super::HideOthers),
- MenuItem::action("Show All", super::ShowAll),
- MenuItem::action("Quit", super::Quit),
- ],
- },
- Menu {
- name: "File",
- items: vec![
- MenuItem::action("New", workspace::NewFile),
- MenuItem::action("New Window", workspace::NewWindow),
- MenuItem::separator(),
- MenuItem::action("Open…", workspace::Open),
- MenuItem::action("Open Recent...", recent_projects::OpenRecent),
- MenuItem::separator(),
- MenuItem::action("Add Folder to Project…", workspace::AddFolderToProject),
- MenuItem::action("Save", workspace::Save { save_intent: None }),
- MenuItem::action("Save As…", workspace::SaveAs),
- MenuItem::action("Save All", workspace::SaveAll { save_intent: None }),
- MenuItem::action(
- "Close Editor",
- workspace::CloseActiveItem { save_intent: None },
- ),
- MenuItem::action("Close Window", workspace::CloseWindow),
- ],
- },
- Menu {
- name: "Edit",
- items: vec![
- MenuItem::os_action("Undo", editor::Undo, OsAction::Undo),
- MenuItem::os_action("Redo", editor::Redo, OsAction::Redo),
- MenuItem::separator(),
- MenuItem::os_action("Cut", editor::Cut, OsAction::Cut),
- MenuItem::os_action("Copy", editor::Copy, OsAction::Copy),
- MenuItem::os_action("Paste", editor::Paste, OsAction::Paste),
- MenuItem::separator(),
- MenuItem::action("Find", search::buffer_search::Deploy { focus: true }),
- MenuItem::action("Find In Project", workspace::NewSearch),
- MenuItem::separator(),
- MenuItem::action("Toggle Line Comment", editor::ToggleComments::default()),
- MenuItem::action("Emoji & Symbols", editor::ShowCharacterPalette),
- ],
- },
- Menu {
- name: "Selection",
- items: vec![
- MenuItem::os_action("Select All", editor::SelectAll, OsAction::SelectAll),
- MenuItem::action("Expand Selection", editor::SelectLargerSyntaxNode),
- MenuItem::action("Shrink Selection", editor::SelectSmallerSyntaxNode),
- MenuItem::separator(),
- MenuItem::action("Add Cursor Above", editor::AddSelectionAbove),
- MenuItem::action("Add Cursor Below", editor::AddSelectionBelow),
- MenuItem::action(
- "Select Next Occurrence",
- editor::SelectNext {
- replace_newest: false,
- },
- ),
- MenuItem::separator(),
- MenuItem::action("Move Line Up", editor::MoveLineUp),
- MenuItem::action("Move Line Down", editor::MoveLineDown),
- MenuItem::action("Duplicate Selection", editor::DuplicateLine),
- ],
- },
- Menu {
- name: "View",
- items: vec![
- MenuItem::action("Zoom In", super::IncreaseBufferFontSize),
- MenuItem::action("Zoom Out", super::DecreaseBufferFontSize),
- MenuItem::action("Reset Zoom", super::ResetBufferFontSize),
- MenuItem::separator(),
- MenuItem::action("Toggle Left Dock", workspace::ToggleLeftDock),
- MenuItem::action("Toggle Right Dock", workspace::ToggleRightDock),
- MenuItem::action("Toggle Bottom Dock", workspace::ToggleBottomDock),
- MenuItem::action("Close All Docks", workspace::CloseAllDocks),
- MenuItem::submenu(Menu {
- name: "Editor Layout",
- items: vec![
- MenuItem::action("Split Up", workspace::SplitUp),
- MenuItem::action("Split Down", workspace::SplitDown),
- MenuItem::action("Split Left", workspace::SplitLeft),
- MenuItem::action("Split Right", workspace::SplitRight),
- ],
- }),
- MenuItem::separator(),
- MenuItem::action("Project Panel", project_panel::ToggleFocus),
- MenuItem::action("Command Palette", command_palette::Toggle),
- MenuItem::action("Diagnostics", diagnostics::Deploy),
- MenuItem::separator(),
- ],
- },
- Menu {
- name: "Go",
- items: vec![
- MenuItem::action("Back", workspace::GoBack),
- MenuItem::action("Forward", workspace::GoForward),
- MenuItem::separator(),
- MenuItem::action("Go to File", file_finder::Toggle),
- MenuItem::action("Go to Symbol in Project", project_symbols::Toggle),
- MenuItem::action("Go to Symbol in Editor", outline::Toggle),
- MenuItem::action("Go to Definition", editor::GoToDefinition),
- MenuItem::action("Go to Type Definition", editor::GoToTypeDefinition),
- MenuItem::action("Find All References", editor::FindAllReferences),
- MenuItem::action("Go to Line/Column", go_to_line::Toggle),
- MenuItem::separator(),
- MenuItem::action("Next Problem", editor::GoToDiagnostic),
- MenuItem::action("Previous Problem", editor::GoToPrevDiagnostic),
- ],
- },
- Menu {
- name: "Window",
- items: vec![
- MenuItem::action("Minimize", super::Minimize),
- MenuItem::action("Zoom", super::Zoom),
- MenuItem::separator(),
- ],
- },
- Menu {
- name: "Help",
- items: vec![
- MenuItem::action("Command Palette", command_palette::Toggle),
- MenuItem::separator(),
- MenuItem::action("View Telemetry", crate::OpenTelemetryLog),
- MenuItem::action("View Dependency Licenses", crate::OpenLicenses),
- MenuItem::action("Show Welcome", workspace::Welcome),
- MenuItem::separator(),
- MenuItem::action("Give us feedback", feedback::feedback_editor::GiveFeedback),
- MenuItem::action(
- "Copy System Specs Into Clipboard",
- feedback::CopySystemSpecsIntoClipboard,
- ),
- MenuItem::action("File Bug Report", feedback::FileBugReport),
- MenuItem::action("Request Feature", feedback::RequestFeature),
- MenuItem::separator(),
- MenuItem::action(
- "Documentation",
- crate::OpenBrowser {
- url: "https://zed.dev/docs".into(),
- },
- ),
- MenuItem::action(
- "Zed Twitter",
- crate::OpenBrowser {
- url: "https://twitter.com/zeddotdev".into(),
- },
- ),
- ],
- },
- ]
-}
@@ -54,7 +54,7 @@ impl OpenListener {
)
}
- pub fn open_urls(&self, urls: Vec<String>) {
+ pub fn open_urls(&self, urls: &[String]) {
self.triggered.store(true, Ordering::Release);
let request = if let Some(server_name) =
urls.first().and_then(|url| url.strip_prefix("zed-cli://"))
@@ -101,7 +101,7 @@ impl OpenListener {
None
}
- fn handle_file_urls(&self, urls: Vec<String>) -> Option<OpenRequest> {
+ fn handle_file_urls(&self, urls: &[String]) -> Option<OpenRequest> {
let paths: Vec<_> = urls
.iter()
.flat_map(|url| url.strip_prefix("file://"))
@@ -187,105 +187,109 @@ pub async fn handle_cli_connection(
};
let mut errored = false;
- match cx
- .update(|cx| workspace::open_paths(&paths, &app_state, None, cx))
- .await
- {
- Ok((workspace, items)) => {
- let mut item_release_futures = Vec::new();
- for (item, path) in items.into_iter().zip(&paths) {
- match item {
- Some(Ok(item)) => {
- if let Some(point) = caret_positions.remove(path) {
- if let Some(active_editor) = item.downcast::<Editor>() {
- active_editor
- .downgrade()
- .update(&mut cx, |editor, cx| {
- let snapshot =
- editor.snapshot(cx).display_snapshot;
- let point = snapshot
- .buffer_snapshot
- .clip_point(point, Bias::Left);
- editor.change_selections(
- Some(Autoscroll::center()),
- cx,
- |s| s.select_ranges([point..point]),
- );
- })
- .log_err();
+ match cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx)) {
+ Ok(task) => match task.await {
+ Ok((workspace, items)) => {
+ let mut item_release_futures = Vec::new();
+
+ for (item, path) in items.into_iter().zip(&paths) {
+ match item {
+ Some(Ok(item)) => {
+ if let Some(point) = caret_positions.remove(path) {
+ if let Some(active_editor) = item.downcast::<Editor>() {
+ workspace
+ .update(&mut cx, |_, cx| {
+ active_editor.update(cx, |editor, cx| {
+ let snapshot = editor
+ .snapshot(cx)
+ .display_snapshot;
+ let point = snapshot
+ .buffer_snapshot
+ .clip_point(point, Bias::Left);
+ editor.change_selections(
+ Some(Autoscroll::center()),
+ cx,
+ |s| s.select_ranges([point..point]),
+ );
+ });
+ })
+ .log_err();
+ }
}
- }
- let released = oneshot::channel();
- cx.update(|cx| {
- item.on_release(
- cx,
- Box::new(move |_| {
- let _ = released.0.send(());
- }),
- )
- .detach();
- });
- item_release_futures.push(released.1);
- }
- Some(Err(err)) => {
- responses
- .send(CliResponse::Stderr {
- message: format!("error opening {:?}: {}", path, err),
+ cx.update(|cx| {
+ let released = oneshot::channel();
+ item.on_release(
+ cx,
+ Box::new(move |_| {
+ let _ = released.0.send(());
+ }),
+ )
+ .detach();
+ item_release_futures.push(released.1);
})
.log_err();
- errored = true;
+ }
+ Some(Err(err)) => {
+ responses
+ .send(CliResponse::Stderr {
+ message: format!(
+ "error opening {:?}: {}",
+ path, err
+ ),
+ })
+ .log_err();
+ errored = true;
+ }
+ None => {}
}
- None => {}
}
- }
- if wait {
- let background = cx.background();
- let wait = async move {
- if paths.is_empty() {
- let (done_tx, done_rx) = oneshot::channel();
- if let Some(workspace) = workspace.upgrade(&cx) {
- let _subscription = cx.update(|cx| {
- cx.observe_release(&workspace, move |_, _| {
+ if wait {
+ let background = cx.background_executor().clone();
+ let wait = async move {
+ if paths.is_empty() {
+ let (done_tx, done_rx) = oneshot::channel();
+ let _subscription = workspace.update(&mut cx, |_, cx| {
+ cx.on_release(move |_, _, _| {
let _ = done_tx.send(());
})
});
- drop(workspace);
let _ = done_rx.await;
- }
- } else {
- let _ =
- futures::future::try_join_all(item_release_futures).await;
- };
- }
- .fuse();
- futures::pin_mut!(wait);
+ } else {
+ let _ = futures::future::try_join_all(item_release_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;
+ 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;
+ }
}
}
}
}
}
- }
- Err(error) => {
- errored = true;
- responses
- .send(CliResponse::Stderr {
- message: format!("error opening {:?}: {}", paths, error),
- })
- .log_err();
- }
+ Err(error) => {
+ errored = true;
+ responses
+ .send(CliResponse::Stderr {
+ message: format!("error opening {:?}: {}", paths, error),
+ })
+ .log_err();
+ }
+ },
+ Err(_) => errored = true,
}
responses
@@ -1,7 +0,0 @@
-#[cfg(test)]
-#[ctor::ctor]
-fn init_logger() {
- if std::env::var("RUST_LOG").is_ok() {
- env_logger::init();
- }
-}
@@ -1,474 +1,486 @@
-pub mod assets;
+mod app_menus;
+mod assets;
pub mod languages;
-pub mod menus;
-pub mod only_instance;
-pub mod open_listener;
-#[cfg(any(test, feature = "test-support"))]
-pub mod test;
-
-use anyhow::Context;
-use assets::Assets;
+mod only_instance;
+mod open_listener;
+
+pub use app_menus::*;
+pub use assets::*;
use assistant::AssistantPanel;
use breadcrumbs::Breadcrumbs;
-pub use client;
-use collab_ui::CollabTitlebarItem; // TODO: Add back toggle collab ui shortcut
use collections::VecDeque;
-pub use editor;
use editor::{Editor, MultiBuffer};
-
-use anyhow::anyhow;
-use feedback::{
- feedback_info_text::FeedbackInfoText, submit_feedback_button::SubmitFeedbackButton,
-};
-use futures::{channel::mpsc, StreamExt};
use gpui::{
- anyhow::{self, Result},
- geometry::vector::vec2f,
- impl_actions,
- platform::{Platform, PromptLevel, TitlebarOptions, WindowBounds, WindowKind, WindowOptions},
- AppContext, AsyncAppContext, Task, ViewContext, WeakViewHandle,
+ actions, point, px, AppContext, Context, FocusableView, PromptLevel, TitlebarOptions, View,
+ ViewContext, VisualContext, WindowBounds, WindowKind, WindowOptions,
};
-pub use lsp;
-use open_listener::OpenListener;
-pub use project;
+pub use only_instance::*;
+pub use open_listener::*;
+
+use anyhow::{anyhow, Context as _};
+use futures::{channel::mpsc, StreamExt};
use project_panel::ProjectPanel;
use quick_action_bar::QuickActionBar;
-use search::{BufferSearchBar, ProjectSearchBar};
-use serde::Deserialize;
-use serde_json::to_string_pretty;
-use settings::{initial_local_settings_content, KeymapFile, SettingsStore};
-use std::{borrow::Cow, str, sync::Arc};
-use terminal_view::terminal_panel::{self, TerminalPanel};
+use search::project_search::ProjectSearchBar;
+use settings::{initial_local_settings_content, load_default_keymap, KeymapFile, Settings};
+use std::{borrow::Cow, ops::Deref, sync::Arc};
+use terminal_view::terminal_panel::TerminalPanel;
use util::{
asset_str,
- channel::ReleaseChannel,
+ channel::{AppCommitSha, ReleaseChannel},
paths::{self, LOCAL_SETTINGS_RELATIVE_PATH},
ResultExt,
};
use uuid::Uuid;
-use welcome::BaseKeymap;
-pub use workspace;
+use workspace::Pane;
use workspace::{
- create_and_open_local_file, dock::PanelHandle,
- notifications::simple_message_notification::MessageNotification, open_new, AppState, NewFile,
- NewWindow, Workspace, WorkspaceSettings,
+ create_and_open_local_file, notifications::simple_message_notification::MessageNotification,
+ open_new, AppState, NewFile, NewWindow, Workspace, WorkspaceSettings,
};
-use zed_actions::*;
-
-#[derive(Deserialize, Clone, PartialEq)]
-pub struct OpenBrowser {
- url: Arc<str>,
-}
+use zed_actions::{OpenBrowser, OpenSettings, OpenZedURL, Quit};
+
+actions!(
+ zed,
+ [
+ About,
+ DebugElements,
+ DecreaseBufferFontSize,
+ Hide,
+ HideOthers,
+ IncreaseBufferFontSize,
+ Minimize,
+ OpenDefaultKeymap,
+ OpenDefaultSettings,
+ OpenKeymap,
+ OpenLicenses,
+ OpenLocalSettings,
+ OpenLog,
+ OpenTelemetryLog,
+ ResetBufferFontSize,
+ ResetDatabase,
+ ShowAll,
+ ToggleFullScreen,
+ Zoom,
+ ]
+);
-impl_actions!(zed, [OpenBrowser]);
-
-pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
- cx.add_action(about);
- cx.add_global_action(|_: &Hide, cx: &mut gpui::AppContext| {
- cx.platform().hide();
- });
- cx.add_global_action(|_: &HideOthers, cx: &mut gpui::AppContext| {
- cx.platform().hide_other_apps();
- });
- cx.add_global_action(|_: &ShowAll, cx: &mut gpui::AppContext| {
- cx.platform().unhide_other_apps();
- });
- cx.add_action(
- |_: &mut Workspace, _: &Minimize, cx: &mut ViewContext<Workspace>| {
- cx.minimize_window();
- },
- );
- cx.add_action(
- |_: &mut Workspace, _: &Zoom, cx: &mut ViewContext<Workspace>| {
- cx.zoom_window();
- },
- );
- cx.add_action(
- |_: &mut Workspace, _: &ToggleFullScreen, cx: &mut ViewContext<Workspace>| {
- cx.toggle_full_screen();
- },
- );
- cx.add_global_action(quit);
- cx.add_global_action(move |action: &OpenZedURL, cx| {
- cx.global::<Arc<OpenListener>>()
- .open_urls(vec![action.url.clone()])
- });
- cx.add_global_action(move |action: &OpenBrowser, cx| cx.platform().open_url(&action.url));
- cx.add_global_action(move |_: &IncreaseBufferFontSize, cx| {
- theme::adjust_font_size(cx, |size| *size += 1.0)
- });
- cx.add_global_action(move |_: &DecreaseBufferFontSize, cx| {
- theme::adjust_font_size(cx, |size| *size -= 1.0)
- });
- cx.add_global_action(move |_: &ResetBufferFontSize, cx| theme::reset_font_size(cx));
- cx.add_global_action(move |_: &install_cli::Install, cx| {
- cx.spawn(|cx| async move {
- install_cli::install_cli(&cx)
- .await
- .context("error creating CLI symlink")
- })
- .detach_and_log_err(cx);
- });
- cx.add_action(
- move |workspace: &mut Workspace, _: &OpenLog, cx: &mut ViewContext<Workspace>| {
- open_log_file(workspace, cx);
- },
- );
- cx.add_action(
- move |workspace: &mut Workspace, _: &OpenLicenses, cx: &mut ViewContext<Workspace>| {
- open_bundled_file(
- workspace,
- asset_str::<Assets>("licenses.md"),
- "Open Source License Attribution",
- "Markdown",
- cx,
- );
- },
- );
- cx.add_action(
- move |workspace: &mut Workspace, _: &OpenTelemetryLog, cx: &mut ViewContext<Workspace>| {
- open_telemetry_log_file(workspace, cx);
- },
- );
- cx.add_action(
- move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
- create_and_open_local_file(&paths::KEYMAP, cx, Default::default).detach_and_log_err(cx);
- },
- );
- cx.add_action(
- move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
- create_and_open_local_file(&paths::SETTINGS, cx, || {
- settings::initial_user_settings_content().as_ref().into()
- })
- .detach_and_log_err(cx);
- },
- );
- cx.add_action(open_local_settings_file);
- cx.add_action(
- move |workspace: &mut Workspace, _: &OpenDefaultKeymap, cx: &mut ViewContext<Workspace>| {
- open_bundled_file(
- workspace,
- settings::default_keymap(),
- "Default Key Bindings",
- "JSON",
- cx,
- );
- },
- );
- cx.add_action(
- move |workspace: &mut Workspace,
- _: &OpenDefaultSettings,
- cx: &mut ViewContext<Workspace>| {
- open_bundled_file(
- workspace,
- settings::default_settings(),
- "Default Settings",
- "JSON",
- cx,
- );
- },
- );
- cx.add_action({
- move |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext<Workspace>| {
- let app_state = workspace.app_state().clone();
- let markdown = app_state.languages.language_for_name("JSON");
- let window = cx.window();
- cx.spawn(|workspace, mut cx| async move {
- let markdown = markdown.await.log_err();
- let content = to_string_pretty(&window.debug_elements(&cx).ok_or_else(|| {
- anyhow!("could not debug elements for window {}", window.id())
- })?)
- .unwrap();
- workspace
- .update(&mut cx, |workspace, cx| {
- workspace.with_local_workspace(cx, move |workspace, cx| {
- let project = workspace.project().clone();
-
- let buffer = project
- .update(cx, |project, cx| {
- project.create_buffer(&content, markdown, cx)
- })
- .expect("creating buffers on a local workspace always succeeds");
- let buffer = cx.add_model(|cx| {
- MultiBuffer::singleton(buffer, cx)
- .with_title("Debug Elements".into())
- });
- workspace.add_item(
- Box::new(cx.add_view(|cx| {
- Editor::for_multibuffer(buffer, Some(project.clone()), cx)
- })),
- cx,
- );
- })
- })?
- .await
- })
- .detach_and_log_err(cx);
- }
- });
- cx.add_action(
- |workspace: &mut Workspace,
- _: &project_panel::ToggleFocus,
- cx: &mut ViewContext<Workspace>| {
- workspace.toggle_panel_focus::<ProjectPanel>(cx);
- },
- );
- cx.add_action(
- |workspace: &mut Workspace,
- _: &collab_ui::collab_panel::ToggleFocus,
- cx: &mut ViewContext<Workspace>| {
- workspace.toggle_panel_focus::<collab_ui::collab_panel::CollabPanel>(cx);
- },
- );
- cx.add_action(
- |workspace: &mut Workspace,
- _: &collab_ui::chat_panel::ToggleFocus,
- cx: &mut ViewContext<Workspace>| {
- workspace.toggle_panel_focus::<collab_ui::chat_panel::ChatPanel>(cx);
- },
- );
- cx.add_action(
- |workspace: &mut Workspace,
- _: &collab_ui::notification_panel::ToggleFocus,
- cx: &mut ViewContext<Workspace>| {
- workspace.toggle_panel_focus::<collab_ui::notification_panel::NotificationPanel>(cx);
- },
- );
- cx.add_action(
- |workspace: &mut Workspace,
- _: &terminal_panel::ToggleFocus,
- cx: &mut ViewContext<Workspace>| {
- workspace.toggle_panel_focus::<TerminalPanel>(cx);
- },
- );
- cx.add_global_action({
- let app_state = Arc::downgrade(&app_state);
- move |_: &NewWindow, cx: &mut AppContext| {
- if let Some(app_state) = app_state.upgrade() {
- open_new(&app_state, cx, |workspace, cx| {
- Editor::new_file(workspace, &Default::default(), cx)
- })
- .detach();
- }
- }
- });
- cx.add_global_action({
- let app_state = Arc::downgrade(&app_state);
- move |_: &NewFile, cx: &mut AppContext| {
- if let Some(app_state) = app_state.upgrade() {
- open_new(&app_state, cx, |workspace, cx| {
- Editor::new_file(workspace, &Default::default(), cx)
- })
- .detach();
- }
- }
+pub fn build_window_options(
+ bounds: Option<WindowBounds>,
+ display_uuid: Option<Uuid>,
+ cx: &mut AppContext,
+) -> WindowOptions {
+ let bounds = bounds.unwrap_or(WindowBounds::Maximized);
+ let display = display_uuid.and_then(|uuid| {
+ cx.displays()
+ .into_iter()
+ .find(|display| display.uuid().ok() == Some(uuid))
});
- load_default_keymap(cx);
+
+ WindowOptions {
+ bounds,
+ titlebar: Some(TitlebarOptions {
+ title: None,
+ appears_transparent: true,
+ traffic_light_position: Some(point(px(8.), px(8.))),
+ }),
+ center: false,
+ focus: false,
+ show: false,
+ kind: WindowKind::Normal,
+ is_movable: true,
+ display_id: display.map(|display| display.id()),
+ }
}
-pub fn initialize_workspace(
- workspace_handle: WeakViewHandle<Workspace>,
- was_deserialized: bool,
- app_state: Arc<AppState>,
- cx: AsyncAppContext,
-) -> Task<Result<()>> {
- cx.spawn(|mut cx| async move {
- workspace_handle.update(&mut cx, |workspace, cx| {
- let workspace_handle = cx.handle();
- cx.subscribe(&workspace_handle, {
- move |workspace, _, event, cx| {
- if let workspace::Event::PaneAdded(pane) = event {
- pane.update(cx, |pane, cx| {
- pane.toolbar().update(cx, |toolbar, cx| {
- let breadcrumbs = cx.add_view(|_| Breadcrumbs::new(workspace));
- toolbar.add_item(breadcrumbs, cx);
- let buffer_search_bar = cx.add_view(BufferSearchBar::new);
- toolbar.add_item(buffer_search_bar.clone(), cx);
- let quick_action_bar = cx.add_view(|_| {
- QuickActionBar::new(buffer_search_bar, workspace)
- });
- toolbar.add_item(quick_action_bar, cx);
- let diagnostic_editor_controls =
- cx.add_view(|_| diagnostics::ToolbarControls::new());
- toolbar.add_item(diagnostic_editor_controls, cx);
- let project_search_bar = cx.add_view(|_| ProjectSearchBar::new());
- toolbar.add_item(project_search_bar, cx);
- let submit_feedback_button =
- cx.add_view(|_| SubmitFeedbackButton::new());
- toolbar.add_item(submit_feedback_button, cx);
- let feedback_info_text = cx.add_view(|_| FeedbackInfoText::new());
- toolbar.add_item(feedback_info_text, cx);
- let lsp_log_item =
- cx.add_view(|_| language_tools::LspLogToolbarItemView::new());
- toolbar.add_item(lsp_log_item, cx);
- let syntax_tree_item = cx
- .add_view(|_| language_tools::SyntaxTreeToolbarItemView::new());
- toolbar.add_item(syntax_tree_item, cx);
- })
- });
- }
+pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
+ cx.observe_new_views(move |workspace: &mut Workspace, cx| {
+ let workspace_handle = cx.view().clone();
+ let center_pane = workspace.active_pane().clone();
+ initialize_pane(workspace, ¢er_pane, cx);
+ cx.subscribe(&workspace_handle, {
+ move |workspace, _, event, cx| {
+ if let workspace::Event::PaneAdded(pane) = event {
+ initialize_pane(workspace, pane, cx);
}
- })
- .detach();
+ }
+ })
+ .detach();
- cx.emit(workspace::Event::PaneAdded(workspace.active_pane().clone()));
+ // cx.emit(workspace2::Event::PaneAdded(
+ // workspace.active_pane().clone(),
+ // ));
+
+ // let collab_titlebar_item =
+ // cx.add_view(|cx| CollabTitlebarItem::new(workspace, &workspace_handle, cx));
+ // workspace.set_titlebar_item(collab_titlebar_item.into_any(), cx);
+
+ let copilot =
+ cx.new_view(|cx| copilot_button::CopilotButton::new(app_state.fs.clone(), cx));
+ let diagnostic_summary =
+ cx.new_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx));
+ let activity_indicator =
+ activity_indicator::ActivityIndicator::new(workspace, app_state.languages.clone(), cx);
+ let active_buffer_language =
+ cx.new_view(|_| language_selector::ActiveBufferLanguage::new(workspace));
+ let vim_mode_indicator = cx.new_view(|cx| vim::ModeIndicator::new(cx));
+ let feedback_button =
+ cx.new_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace));
+ let cursor_position = cx.new_view(|_| editor::items::CursorPosition::new());
+ workspace.status_bar().update(cx, |status_bar, cx| {
+ status_bar.add_left_item(diagnostic_summary, cx);
+ status_bar.add_left_item(activity_indicator, cx);
+ status_bar.add_right_item(feedback_button, cx);
+ // status_bar.add_right_item(copilot, cx);
+ status_bar.add_right_item(copilot, cx);
+ status_bar.add_right_item(active_buffer_language, cx);
+ status_bar.add_right_item(vim_mode_indicator, cx);
+ status_bar.add_right_item(cursor_position, cx);
+ });
- let collab_titlebar_item =
- cx.add_view(|cx| CollabTitlebarItem::new(workspace, &workspace_handle, cx));
- workspace.set_titlebar_item(collab_titlebar_item.into_any(), cx);
+ auto_update::notify_of_any_new_update(cx);
- let copilot =
- cx.add_view(|cx| copilot_button::CopilotButton::new(app_state.fs.clone(), cx));
- let diagnostic_summary =
- cx.add_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx));
- let activity_indicator = activity_indicator::ActivityIndicator::new(
- workspace,
- app_state.languages.clone(),
- cx,
- );
- let active_buffer_language =
- cx.add_view(|_| language_selector::ActiveBufferLanguage::new(workspace));
- let vim_mode_indicator = cx.add_view(|cx| vim::ModeIndicator::new(cx));
- let feedback_button = cx.add_view(|_| {
- feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace)
- });
- let cursor_position = cx.add_view(|_| editor::items::CursorPosition::new());
- workspace.status_bar().update(cx, |status_bar, cx| {
- status_bar.add_left_item(diagnostic_summary, cx);
- status_bar.add_left_item(activity_indicator, cx);
-
- status_bar.add_right_item(feedback_button, cx);
- status_bar.add_right_item(copilot, cx);
- status_bar.add_right_item(active_buffer_language, cx);
- status_bar.add_right_item(vim_mode_indicator, cx);
- status_bar.add_right_item(cursor_position, cx);
- });
+ vim::observe_keystrokes(cx);
- auto_update::notify_of_any_new_update(cx.weak_handle(), cx);
+ let handle = cx.view().downgrade();
+ cx.on_window_should_close(move |cx| {
+ handle
+ .update(cx, |workspace, cx| {
+ workspace.close_window(&Default::default(), cx);
+ false
+ })
+ .unwrap_or(true)
+ });
- vim::observe_keystrokes(cx);
+ cx.spawn(|workspace_handle, mut cx| async move {
+ let project_panel = ProjectPanel::load(workspace_handle.clone(), cx.clone());
+ let terminal_panel = TerminalPanel::load(workspace_handle.clone(), cx.clone());
+ let assistant_panel = AssistantPanel::load(workspace_handle.clone(), cx.clone());
+ let channels_panel =
+ collab_ui::collab_panel::CollabPanel::load(workspace_handle.clone(), cx.clone());
+ let chat_panel =
+ collab_ui::chat_panel::ChatPanel::load(workspace_handle.clone(), cx.clone());
+ let notification_panel = collab_ui::notification_panel::NotificationPanel::load(
+ workspace_handle.clone(),
+ cx.clone(),
+ );
+ let (
+ project_panel,
+ terminal_panel,
+ assistant_panel,
+ channels_panel,
+ chat_panel,
+ notification_panel,
+ ) = futures::try_join!(
+ project_panel,
+ terminal_panel,
+ assistant_panel,
+ channels_panel,
+ chat_panel,
+ notification_panel,
+ )?;
+
+ workspace_handle.update(&mut cx, |workspace, cx| {
+ workspace.add_panel(project_panel, cx);
+ workspace.add_panel(terminal_panel, cx);
+ workspace.add_panel(assistant_panel, cx);
+ workspace.add_panel(channels_panel, cx);
+ workspace.add_panel(chat_panel, cx);
+ workspace.add_panel(notification_panel, cx);
+
+ // if !was_deserialized
+ // && workspace
+ // .project()
+ // .read(cx)
+ // .visible_worktrees(cx)
+ // .any(|tree| {
+ // tree.read(cx)
+ // .root_entry()
+ // .map_or(false, |entry| entry.is_dir())
+ // })
+ // {
+ // workspace.toggle_dock(project_panel_position, cx);
+ // }
+ cx.focus_self();
+ })
+ })
+ .detach();
- cx.on_window_should_close(|workspace, cx| {
- if let Some(task) = workspace.close(&Default::default(), cx) {
- task.detach_and_log_err(cx);
+ workspace
+ .register_action(about)
+ .register_action(|_, _: &Hide, cx| {
+ cx.hide();
+ })
+ .register_action(|_, _: &HideOthers, cx| {
+ cx.hide_other_apps();
+ })
+ .register_action(|_, _: &ShowAll, cx| {
+ cx.unhide_other_apps();
+ })
+ .register_action(|_, _: &Minimize, cx| {
+ cx.minimize_window();
+ })
+ .register_action(|_, _: &Zoom, cx| {
+ cx.zoom_window();
+ })
+ .register_action(|_, _: &ToggleFullScreen, cx| {
+ cx.toggle_full_screen();
+ })
+ .register_action(quit)
+ .register_action(|_, action: &OpenZedURL, cx| {
+ cx.global::<Arc<OpenListener>>()
+ .open_urls(&[action.url.clone()])
+ })
+ .register_action(|_, action: &OpenBrowser, cx| cx.open_url(&action.url))
+ .register_action(move |_, _: &IncreaseBufferFontSize, cx| {
+ theme::adjust_font_size(cx, |size| *size += px(1.0))
+ })
+ .register_action(move |_, _: &DecreaseBufferFontSize, cx| {
+ theme::adjust_font_size(cx, |size| *size -= px(1.0))
+ })
+ .register_action(move |_, _: &ResetBufferFontSize, cx| theme::reset_font_size(cx))
+ .register_action(|_, _: &install_cli::Install, cx| {
+ cx.spawn(|_, cx| async move {
+ install_cli::install_cli(cx.deref())
+ .await
+ .context("error creating CLI symlink")
+ })
+ .detach_and_log_err(cx);
+ })
+ .register_action(|workspace, _: &OpenLog, cx| {
+ open_log_file(workspace, cx);
+ })
+ .register_action(|workspace, _: &OpenLicenses, cx| {
+ open_bundled_file(
+ workspace,
+ asset_str::<Assets>("licenses.md"),
+ "Open Source License Attribution",
+ "Markdown",
+ cx,
+ );
+ })
+ .register_action(
+ move |workspace: &mut Workspace,
+ _: &OpenTelemetryLog,
+ cx: &mut ViewContext<Workspace>| {
+ open_telemetry_log_file(workspace, cx);
+ },
+ )
+ .register_action(
+ move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
+ create_and_open_local_file(&paths::KEYMAP, cx, Default::default)
+ .detach_and_log_err(cx);
+ },
+ )
+ .register_action(
+ move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
+ create_and_open_local_file(&paths::SETTINGS, cx, || {
+ settings::initial_user_settings_content().as_ref().into()
+ })
+ .detach_and_log_err(cx);
+ },
+ )
+ .register_action(open_local_settings_file)
+ .register_action(
+ move |workspace: &mut Workspace,
+ _: &OpenDefaultKeymap,
+ cx: &mut ViewContext<Workspace>| {
+ open_bundled_file(
+ workspace,
+ settings::default_keymap(),
+ "Default Key Bindings",
+ "JSON",
+ cx,
+ );
+ },
+ )
+ .register_action(
+ move |workspace: &mut Workspace,
+ _: &OpenDefaultSettings,
+ cx: &mut ViewContext<Workspace>| {
+ open_bundled_file(
+ workspace,
+ settings::default_settings(),
+ "Default Settings",
+ "JSON",
+ cx,
+ );
+ },
+ )
+ //todo!()
+ // cx.add_action({
+ // move |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext<Workspace>| {
+ // let app_state = workspace.app_state().clone();
+ // let markdown = app_state.languages.language_for_name("JSON");
+ // let window = cx.window();
+ // cx.spawn(|workspace, mut cx| async move {
+ // let markdown = markdown.await.log_err();
+ // let content = to_string_pretty(&window.debug_elements(&cx).ok_or_else(|| {
+ // anyhow!("could not debug elements for window {}", window.id())
+ // })?)
+ // .unwrap();
+ // workspace
+ // .update(&mut cx, |workspace, cx| {
+ // workspace.with_local_workspace(cx, move |workspace, cx| {
+ // let project = workspace.project().clone();
+ // let buffer = project
+ // .update(cx, |project, cx| {
+ // project.create_buffer(&content, markdown, cx)
+ // })
+ // .expect("creating buffers on a local workspace always succeeds");
+ // let buffer = cx.add_model(|cx| {
+ // MultiBuffer::singleton(buffer, cx)
+ // .with_title("Debug Elements".into())
+ // });
+ // workspace.add_item(
+ // Box::new(cx.add_view(|cx| {
+ // Editor::for_multibuffer(buffer, Some(project.clone()), cx)
+ // })),
+ // cx,
+ // );
+ // })
+ // })?
+ // .await
+ // })
+ // .detach_and_log_err(cx);
+ // }
+ // });
+ // .register_action(
+ // |workspace: &mut Workspace,
+ // _: &project_panel::ToggleFocus,
+ // cx: &mut ViewContext<Workspace>| {
+ // workspace.toggle_panel_focus::<ProjectPanel>(cx);
+ // },
+ // );
+ // cx.add_action(
+ // |workspace: &mut Workspace,
+ // _: &collab_ui::collab_panel::ToggleFocus,
+ // cx: &mut ViewContext<Workspace>| {
+ // workspace.toggle_panel_focus::<collab_ui::collab_panel::CollabPanel>(cx);
+ // },
+ // );
+ // cx.add_action(
+ // |workspace: &mut Workspace,
+ // _: &collab_ui::chat_panel::ToggleFocus,
+ // cx: &mut ViewContext<Workspace>| {
+ // workspace.toggle_panel_focus::<collab_ui::chat_panel::ChatPanel>(cx);
+ // },
+ // );
+ // cx.add_action(
+ // |workspace: &mut Workspace,
+ // _: &collab_ui::notification_panel::ToggleFocus,
+ // cx: &mut ViewContext<Workspace>| {
+ // workspace.toggle_panel_focus::<collab_ui::notification_panel::NotificationPanel>(cx);
+ // },
+ // );
+ // cx.add_action(
+ // |workspace: &mut Workspace,
+ // _: &terminal_panel::ToggleFocus,
+ // cx: &mut ViewContext<Workspace>| {
+ // workspace.toggle_panel_focus::<TerminalPanel>(cx);
+ // },
+ // );
+ .register_action({
+ let app_state = Arc::downgrade(&app_state);
+ move |_, _: &NewWindow, cx| {
+ if let Some(app_state) = app_state.upgrade() {
+ open_new(&app_state, cx, |workspace, cx| {
+ Editor::new_file(workspace, &Default::default(), cx)
+ })
+ .detach();
+ }
+ }
+ })
+ .register_action({
+ let app_state = Arc::downgrade(&app_state);
+ move |_, _: &NewFile, cx| {
+ if let Some(app_state) = app_state.upgrade() {
+ open_new(&app_state, cx, |workspace, cx| {
+ Editor::new_file(workspace, &Default::default(), cx)
+ })
+ .detach();
+ }
}
- false
});
- })?;
- let project_panel = ProjectPanel::load(workspace_handle.clone(), cx.clone());
- let terminal_panel = TerminalPanel::load(workspace_handle.clone(), cx.clone());
- let assistant_panel = AssistantPanel::load(workspace_handle.clone(), cx.clone());
- let channels_panel =
- collab_ui::collab_panel::CollabPanel::load(workspace_handle.clone(), cx.clone());
- let chat_panel =
- collab_ui::chat_panel::ChatPanel::load(workspace_handle.clone(), cx.clone());
- let notification_panel = collab_ui::notification_panel::NotificationPanel::load(
- workspace_handle.clone(),
- cx.clone(),
- );
- let (
- project_panel,
- terminal_panel,
- assistant_panel,
- channels_panel,
- chat_panel,
- notification_panel,
- ) = futures::try_join!(
- project_panel,
- terminal_panel,
- assistant_panel,
- channels_panel,
- chat_panel,
- notification_panel,
- )?;
- workspace_handle.update(&mut cx, |workspace, cx| {
- let project_panel_position = project_panel.position(cx);
- workspace.add_panel_with_extra_event_handler(
- project_panel,
- cx,
- |workspace, _, event, cx| match event {
- project_panel::Event::NewSearchInDirectory { dir_entry } => {
- search::ProjectSearchView::new_search_in_directory(workspace, dir_entry, cx)
- }
- project_panel::Event::ActivatePanel => {
- workspace.focus_panel::<ProjectPanel>(cx);
- }
- _ => {}
- },
- );
- workspace.add_panel(terminal_panel, cx);
- workspace.add_panel(assistant_panel, cx);
- workspace.add_panel(channels_panel, cx);
- workspace.add_panel(chat_panel, cx);
- workspace.add_panel(notification_panel, cx);
-
- if !was_deserialized
- && workspace
- .project()
- .read(cx)
- .visible_worktrees(cx)
- .any(|tree| {
- tree.read(cx)
- .root_entry()
- .map_or(false, |entry| entry.is_dir())
- })
- {
- workspace.toggle_dock(project_panel_position, cx);
- }
- cx.focus_self();
- })?;
- Ok(())
+ workspace.focus_handle(cx).focus(cx);
+ //todo!()
+ // load_default_keymap(cx);
})
+ .detach();
}
-pub fn build_window_options(
- bounds: Option<WindowBounds>,
- display: Option<Uuid>,
- platform: &dyn Platform,
-) -> WindowOptions<'static> {
- let bounds = bounds.unwrap_or(WindowBounds::Maximized);
- let screen = display.and_then(|display| platform.screen_by_id(display));
+fn initialize_pane(workspace: &mut Workspace, pane: &View<Pane>, cx: &mut ViewContext<Workspace>) {
+ pane.update(cx, |pane, cx| {
+ pane.toolbar().update(cx, |toolbar, cx| {
+ let breadcrumbs = cx.new_view(|_| Breadcrumbs::new());
+ toolbar.add_item(breadcrumbs, cx);
+ let buffer_search_bar = cx.new_view(search::BufferSearchBar::new);
+ toolbar.add_item(buffer_search_bar.clone(), cx);
+
+ let quick_action_bar =
+ cx.new_view(|_| QuickActionBar::new(buffer_search_bar, workspace));
+ toolbar.add_item(quick_action_bar, cx);
+ let diagnostic_editor_controls = cx.new_view(|_| diagnostics::ToolbarControls::new());
+ toolbar.add_item(diagnostic_editor_controls, cx);
+ let project_search_bar = cx.new_view(|_| ProjectSearchBar::new());
+ toolbar.add_item(project_search_bar, cx);
+ let lsp_log_item = cx.new_view(|_| language_tools::LspLogToolbarItemView::new());
+ toolbar.add_item(lsp_log_item, cx);
+ let syntax_tree_item =
+ cx.new_view(|_| language_tools::SyntaxTreeToolbarItemView::new());
+ toolbar.add_item(syntax_tree_item, cx);
+ })
+ });
+}
- WindowOptions {
- titlebar: Some(TitlebarOptions {
- title: None,
- appears_transparent: true,
- traffic_light_position: Some(vec2f(8., 8.)),
- }),
- center: false,
- focus: false,
- show: false,
- kind: WindowKind::Normal,
- is_movable: true,
- bounds,
- screen,
+fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext<Workspace>) {
+ use std::fmt::Write as _;
+
+ let app_name = cx.global::<ReleaseChannel>().display_name();
+ let version = env!("CARGO_PKG_VERSION");
+ let mut message = format!("{app_name} {version}");
+ if let Some(sha) = cx.try_global::<AppCommitSha>() {
+ write!(&mut message, "\n\n{}", sha.0).unwrap();
}
+
+ let prompt = cx.prompt(PromptLevel::Info, &message, &["OK"]);
+ cx.foreground_executor()
+ .spawn(async {
+ prompt.await.ok();
+ })
+ .detach();
}
-fn quit(_: &Quit, cx: &mut gpui::AppContext) {
- let should_confirm = settings::get::<WorkspaceSettings>(cx).confirm_quit;
- cx.spawn(|mut cx| async move {
- let mut workspace_windows = cx
- .windows()
- .into_iter()
- .filter_map(|window| window.downcast::<Workspace>())
- .collect::<Vec<_>>();
+fn quit(_: &mut Workspace, _: &Quit, cx: &mut gpui::ViewContext<Workspace>) {
+ let should_confirm = WorkspaceSettings::get_global(cx).confirm_quit;
+ cx.spawn(|_, mut cx| async move {
+ let mut workspace_windows = cx.update(|_, cx| {
+ cx.windows()
+ .into_iter()
+ .filter_map(|window| window.downcast::<Workspace>())
+ .collect::<Vec<_>>()
+ })?;
// If multiple windows have unsaved changes, and need a save prompt,
// prompt in the active window before switching to a different window.
- workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false));
-
- if let (true, Some(window)) = (should_confirm, workspace_windows.first().copied()) {
- let answer = window.prompt(
- PromptLevel::Info,
- "Are you sure you want to quit?",
- &["Quit", "Cancel"],
- &mut cx,
- );
+ cx.update(|_, cx| {
+ workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false));
+ })
+ .log_err();
+
+ if let (true, Some(_)) = (should_confirm, workspace_windows.first().copied()) {
+ let answer = cx
+ .update(|_, cx| {
+ cx.prompt(
+ PromptLevel::Info,
+ "Are you sure you want to quit?",
+ &["Quit", "Cancel"],
+ )
+ })
+ .log_err();
- if let Some(mut answer) = answer {
- let answer = answer.next().await;
+ if let Some(answer) = answer {
+ let answer = answer.await.ok();
if answer != Some(0) {
return Ok(());
}
@@ -477,29 +489,27 @@ fn quit(_: &Quit, cx: &mut gpui::AppContext) {
// If the user cancels any save prompt, then keep the app open.
for window in workspace_windows {
- if let Some(should_close) = window.update_root(&mut cx, |workspace, cx| {
- workspace.prepare_to_close(true, cx)
- }) {
+ if let Some(should_close) = window
+ .update(&mut cx, |workspace, cx| {
+ workspace.prepare_to_close(true, cx)
+ })
+ .log_err()
+ {
if !should_close.await? {
return Ok(());
}
}
}
- cx.platform().quit();
+ cx.update(|_, cx| {
+ cx.quit();
+ })?;
anyhow::Ok(())
})
.detach_and_log_err(cx);
}
-fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext<Workspace>) {
- let app_name = cx.global::<ReleaseChannel>().display_name();
- let version = env!("CARGO_PKG_VERSION");
- cx.prompt(PromptLevel::Info, &format!("{app_name} {version}"), &["OK"]);
-}
-
fn open_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
const MAX_LINES: usize = 1000;
-
workspace
.with_local_workspace(cx, move |workspace, cx| {
let fs = workspace.app_state().fs.clone();
@@ -531,12 +541,12 @@ fn open_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
.expect("creating buffers on a local workspace always succeeds");
buffer.update(cx, |buffer, cx| buffer.edit([(0..0, log)], None, cx));
- let buffer = cx.add_model(|cx| {
+ let buffer = cx.new_model(|cx| {
MultiBuffer::singleton(buffer, cx).with_title("Log".into())
});
workspace.add_item(
Box::new(
- cx.add_view(|cx| {
+ cx.new_view(|cx| {
Editor::for_multibuffer(buffer, Some(project), cx)
}),
),
@@ -550,37 +560,28 @@ fn open_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
.detach();
}
-pub fn load_default_keymap(cx: &mut AppContext) {
- for path in ["keymaps/default.json", "keymaps/vim.json"] {
- KeymapFile::load_asset(path, cx).unwrap();
- }
-
- if let Some(asset_path) = settings::get::<BaseKeymap>(cx).asset_path() {
- KeymapFile::load_asset(asset_path, cx).unwrap();
- }
-}
-
pub fn handle_keymap_file_changes(
mut user_keymap_file_rx: mpsc::UnboundedReceiver<String>,
cx: &mut AppContext,
) {
- cx.spawn(move |mut cx| async move {
- let mut settings_subscription = None;
+ cx.spawn(move |cx| async move {
+ // let mut settings_subscription = None;
while let Some(user_keymap_content) = user_keymap_file_rx.next().await {
- if let Ok(keymap_content) = KeymapFile::parse(&user_keymap_content) {
- cx.update(|cx| reload_keymaps(cx, &keymap_content));
-
- let mut old_base_keymap = cx.read(|cx| *settings::get::<BaseKeymap>(cx));
- drop(settings_subscription);
- settings_subscription = Some(cx.update(|cx| {
- cx.observe_global::<SettingsStore, _>(move |cx| {
- let new_base_keymap = *settings::get::<BaseKeymap>(cx);
- if new_base_keymap != old_base_keymap {
- old_base_keymap = new_base_keymap.clone();
- reload_keymaps(cx, &keymap_content);
- }
- })
- }));
+ if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() {
+ cx.update(|cx| reload_keymaps(cx, &keymap_content)).ok();
+
+ // todo!()
+ // let mut old_base_keymap = cx.read(|cx| *settings::get::<BaseKeymap>(cx));
+ // drop(settings_subscription);
+ // settings_subscription = Some(cx.update(|cx| {
+ // cx.observe_global::<SettingsStore, _>(move |cx| {
+ // let new_base_keymap = *settings::get::<BaseKeymap>(cx);
+ // if new_base_keymap != old_base_keymap {
+ // old_base_keymap = new_base_keymap.clone();
+ // reload_keymaps(cx, &keymap_content);
+ // }
+ // })
+ // }));
}
}
})
@@ -1,192 +0,0 @@
-[package]
-description = "The fast, collaborative code editor."
-edition = "2021"
-name = "zed2"
-version = "2.0.0"
-publish = false
-
-[lib]
-name = "zed2"
-path = "src/zed2.rs"
-doctest = false
-
-[[bin]]
-name = "zed2"
-path = "src/main.rs"
-
-[dependencies]
-ai = { package = "ai2", path = "../ai2"}
-audio = { package = "audio2", path = "../audio2" }
-activity_indicator = { package = "activity_indicator2", path = "../activity_indicator2"}
-auto_update = { package = "auto_update2", path = "../auto_update2" }
-breadcrumbs = { package = "breadcrumbs2", path = "../breadcrumbs2" }
-call = { package = "call2", path = "../call2" }
-channel = { package = "channel2", path = "../channel2" }
-cli = { path = "../cli" }
-collab_ui = { package = "collab_ui2", path = "../collab_ui2" }
-collections = { path = "../collections" }
-command_palette = { package="command_palette2", path = "../command_palette2" }
-# component_test = { path = "../component_test" }
-client = { package = "client2", path = "../client2" }
-# clock = { path = "../clock" }
-copilot = { package = "copilot2", path = "../copilot2" }
-copilot_button = { package = "copilot_button2", path = "../copilot_button2" }
-diagnostics = { package = "diagnostics2", path = "../diagnostics2" }
-db = { package = "db2", path = "../db2" }
-editor = { package="editor2", path = "../editor2" }
-feedback = { package="feedback2", path = "../feedback2" }
-file_finder = { package="file_finder2", path = "../file_finder2" }
-search = { package = "search2", path = "../search2" }
-fs = { package = "fs2", path = "../fs2" }
-fsevent = { path = "../fsevent" }
-go_to_line = { package = "go_to_line2", path = "../go_to_line2" }
-gpui = { package = "gpui2", path = "../gpui2" }
-install_cli = { package = "install_cli2", path = "../install_cli2" }
-journal = { package = "journal2", path = "../journal2" }
-language = { package = "language2", path = "../language2" }
-language_selector = { package = "language_selector2", path = "../language_selector2" }
-lsp = { package = "lsp2", path = "../lsp2" }
-menu = { package = "menu2", path = "../menu2" }
-language_tools = { package = "language_tools2", path = "../language_tools2" }
-node_runtime = { path = "../node_runtime" }
-notifications = { package = "notifications2", path = "../notifications2" }
-assistant = { package = "assistant2", path = "../assistant2" }
-outline = { package = "outline2", path = "../outline2" }
-# plugin_runtime = { path = "../plugin_runtime",optional = true }
-project = { package = "project2", path = "../project2" }
-project_panel = { package = "project_panel2", path = "../project_panel2" }
-project_symbols = { package = "project_symbols2", path = "../project_symbols2" }
-quick_action_bar = { package = "quick_action_bar2", path = "../quick_action_bar2" }
-recent_projects = { package = "recent_projects2", path = "../recent_projects2" }
-rope = { package = "rope2", path = "../rope2"}
-rpc = { package = "rpc2", path = "../rpc2" }
-settings = { package = "settings2", path = "../settings2" }
-feature_flags = { package = "feature_flags2", path = "../feature_flags2" }
-sum_tree = { path = "../sum_tree" }
-shellexpand = "2.1.0"
-text = { package = "text2", path = "../text2" }
-terminal_view = { package = "terminal_view2", path = "../terminal_view2" }
-theme = { package = "theme2", path = "../theme2" }
-theme_selector = { package = "theme_selector2", path = "../theme_selector2" }
-util = { path = "../util" }
-semantic_index = { package = "semantic_index2", path = "../semantic_index2" }
-vim = { package = "vim2", path = "../vim2" }
-workspace = { package = "workspace2", path = "../workspace2" }
-welcome = { package = "welcome2", path = "../welcome2" }
-zed_actions = {package = "zed_actions2", path = "../zed_actions2"}
-anyhow.workspace = true
-async-compression.workspace = true
-async-tar = "0.4.2"
-async-recursion = "0.3"
-async-trait.workspace = true
-backtrace = "0.3"
-chrono = "0.4"
-ctor.workspace = true
-env_logger.workspace = true
-futures.workspace = true
-ignore = "0.4"
-image = "0.23"
-indexmap = "1.6.2"
-isahc.workspace = true
-lazy_static.workspace = true
-libc = "0.2"
-log.workspace = true
-num_cpus = "1.13.0"
-parking_lot.workspace = true
-postage.workspace = true
-rand.workspace = true
-regex.workspace = true
-rsa = "0.4"
-rust-embed.workspace = true
-serde.workspace = true
-serde_derive.workspace = true
-serde_json.workspace = true
-schemars.workspace = true
-simplelog = "0.9"
-smallvec.workspace = true
-smol.workspace = true
-tempdir.workspace = true
-thiserror.workspace = true
-tiny_http = "0.8"
-toml.workspace = true
-tree-sitter.workspace = true
-tree-sitter-bash.workspace = true
-tree-sitter-c.workspace = true
-tree-sitter-cpp.workspace = true
-tree-sitter-css.workspace = true
-tree-sitter-elixir.workspace = true
-tree-sitter-elm.workspace = true
-tree-sitter-embedded-template.workspace = true
-tree-sitter-glsl.workspace = true
-tree-sitter-go.workspace = true
-tree-sitter-heex.workspace = true
-tree-sitter-json.workspace = true
-tree-sitter-rust.workspace = true
-tree-sitter-markdown.workspace = true
-tree-sitter-python.workspace = true
-tree-sitter-toml.workspace = true
-tree-sitter-typescript.workspace = true
-tree-sitter-ruby.workspace = true
-tree-sitter-html.workspace = true
-tree-sitter-php.workspace = true
-tree-sitter-scheme.workspace = true
-tree-sitter-svelte.workspace = true
-tree-sitter-racket.workspace = true
-tree-sitter-yaml.workspace = true
-tree-sitter-lua.workspace = true
-tree-sitter-nix.workspace = true
-tree-sitter-nu.workspace = true
-tree-sitter-vue.workspace = true
-tree-sitter-uiua.workspace = true
-
-url = "2.2"
-urlencoding = "2.1.2"
-uuid.workspace = true
-
-[dev-dependencies]
-call = { package = "call2", path = "../call2", features = ["test-support"] }
-# client = { path = "../client", features = ["test-support"] }
-# editor = { path = "../editor", features = ["test-support"] }
-# gpui = { path = "../gpui", features = ["test-support"] }
-gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
-language = { package = "language2", path = "../language2", features = ["test-support"] }
-# lsp = { path = "../lsp", features = ["test-support"] }
-project = { package = "project2", path = "../project2", features = ["test-support"] }
-# rpc = { path = "../rpc", features = ["test-support"] }
-# settings = { path = "../settings", features = ["test-support"] }
-text = { package = "text2", path = "../text2", features = ["test-support"] }
-# util = { path = "../util", features = ["test-support"] }
-# workspace = { path = "../workspace", features = ["test-support"] }
-unindent.workspace = true
-
-[package.metadata.bundle-dev]
-icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
-identifier = "dev.zed.Zed-Dev"
-name = "Zed Dev"
-osx_minimum_system_version = "10.15.7"
-osx_info_plist_exts = ["resources/info/*"]
-osx_url_schemes = ["zed-dev"]
-
-[package.metadata.bundle-nightly]
-icon = ["resources/app-icon-nightly@2x.png", "resources/app-icon-nightly.png"]
-identifier = "dev.zed.Zed-Nightly"
-name = "Zed Nightly"
-osx_minimum_system_version = "10.15.7"
-osx_info_plist_exts = ["resources/info/*"]
-osx_url_schemes = ["zed-nightly"]
-
-[package.metadata.bundle-preview]
-icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
-identifier = "dev.zed.Zed-Preview"
-name = "Zed Preview"
-osx_minimum_system_version = "10.15.7"
-osx_info_plist_exts = ["resources/info/*"]
-osx_url_schemes = ["zed-preview"]
-
-[package.metadata.bundle-stable]
-icon = ["resources/app-icon@2x.png", "resources/app-icon.png"]
-identifier = "dev.zed.Zed"
-name = "Zed"
-osx_minimum_system_version = "10.15.7"
-osx_info_plist_exts = ["resources/info/*"]
-osx_url_schemes = ["zed"]
@@ -1,44 +0,0 @@
-use std::process::Command;
-
-fn main() {
- println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.15.7");
-
- println!("cargo:rerun-if-env-changed=ZED_BUNDLE");
- if std::env::var("ZED_BUNDLE").ok().as_deref() == Some("true") {
- // Find WebRTC.framework in the Frameworks folder when running as part of an application bundle.
- println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path/../Frameworks");
- } else {
- // Find WebRTC.framework as a sibling of the executable when running outside of an application bundle.
- println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path");
- }
-
- // Weakly link ReplayKit to ensure Zed can be used on macOS 10.15+.
- println!("cargo:rustc-link-arg=-Wl,-weak_framework,ReplayKit");
-
- // Seems to be required to enable Swift concurrency
- println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/swift");
-
- // Register exported Objective-C selectors, protocols, etc
- println!("cargo:rustc-link-arg=-Wl,-ObjC");
-
- // Populate git sha environment variable if git is available
- println!("cargo:rerun-if-changed=.git/logs/HEAD");
- if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() {
- if output.status.success() {
- let git_sha = String::from_utf8_lossy(&output.stdout);
- let git_sha = git_sha.trim();
-
- println!("cargo:rustc-env=ZED_COMMIT_SHA={git_sha}");
-
- if let Ok(build_profile) = std::env::var("PROFILE") {
- if build_profile == "release" {
- // This is currently the best way to make `cargo build ...`'s build script
- // to print something to stdout without extra verbosity.
- println!(
- "cargo:warning=Info: using '{git_sha}' hash for ZED_COMMIT_SHA env var"
- );
- }
- }
- }
- }
-}
@@ -1,62 +0,0 @@
-<key>CFBundleDocumentTypes</key>
-<array>
- <dict>
- <key>CFBundleTypeIconFile</key>
- <string>Document</string>
- <key>CFBundleTypeRole</key>
- <string>Editor</string>
- <key>LSHandlerRank</key>
- <string>Alternate</string>
- <key>LSItemContentTypes</key>
- <array>
- <string>public.text</string>
- <string>public.plain-text</string>
- <string>public.utf8-plain-text</string>
- </array>
- </dict>
- <dict>
- <key>CFBundleTypeIconFile</key>
- <string>Document</string>
- <key>CFBundleTypeName</key>
- <string>Zed Text Document</string>
- <key>CFBundleTypeRole</key>
- <string>Editor</string>
- <key>CFBundleTypeOSTypes</key>
- <array>
- <string>****</string>
- </array>
- <key>LSHandlerRank</key>
- <string>Default</string>
- <key>CFBundleTypeExtensions</key>
- <array>
- <string>Gemfile</string>
- <string>c</string>
- <string>c++</string>
- <string>cc</string>
- <string>cpp</string>
- <string>css</string>
- <string>erb</string>
- <string>ex</string>
- <string>exs</string>
- <string>go</string>
- <string>h</string>
- <string>h++</string>
- <string>hh</string>
- <string>hpp</string>
- <string>html</string>
- <string>js</string>
- <string>json</string>
- <string>jsx</string>
- <string>md</string>
- <string>py</string>
- <string>rb</string>
- <string>rkt</string>
- <string>rs</string>
- <string>scm</string>
- <string>toml</string>
- <string>ts</string>
- <string>tsx</string>
- <string>txt</string>
- </array>
- </dict>
-</array>
@@ -1,24 +0,0 @@
-<key>NSSystemAdministrationUsageDescription</key>
-<string>The operation being performed by a program in Zed requires elevated permission.</string>
-<key>NSAppleEventsUsageDescription</key>
-<string>An application in Zed wants to use AppleScript.</string>
-<key>NSBluetoothAlwaysUsageDescription</key>
-<string>An application in Zed wants to use Bluetooth.</string>
-<key>NSCalendarsUsageDescription</key>
-<string>An application in Zed wants to use Calendar data.</string>
-<key>NSCameraUsageDescription</key>
-<string>An application in Zed wants to use the camera.</string>
-<key>NSContactsUsageDescription</key>
-<string>An application in Zed wants to use your contacts.</string>
-<key>NSLocationAlwaysUsageDescription</key>
-<string>An application in Zed wants to use your location information, even in the background.</string>
-<key>NSLocationUsageDescription</key>
-<string>An application in Zed wants to use your location information.</string>
-<key>NSLocationWhenInUseUsageDescription</key>
-<string>An application in Zed wants to use your location information while active.</string>
-<key>NSMicrophoneUsageDescription</key>
-<string>An application in Zed wants to use your microphone.</string>
-<key>NSSpeechRecognitionUsageDescription</key>
-<string>An application in Zed wants to use speech recognition.</string>
-<key>NSRemindersUsageDescription</key>
-<string>An application in Zed wants to use your reminders.</string>
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>com.apple.security.automation.apple-events</key>
- <true/>
- <key>com.apple.security.cs.allow-jit</key>
- <true/>
- <key>com.apple.security.device.audio-input</key>
- <true/>
- <key>com.apple.security.device.camera</key>
- <true/>
- <key>com.apple.security.personal-information.addressbook</key>
- <true/>
- <key>com.apple.security.personal-information.calendars</key>
- <true/>
- <key>com.apple.security.personal-information.location</key>
- <true/>
- <key>com.apple.security.personal-information.photos-library</key>
- <true/>
- <!-- <key>com.apple.security.cs.disable-library-validation</key>
- <true/> -->
-</dict>
-</plist>
@@ -1,35 +0,0 @@
-use anyhow::anyhow;
-
-use gpui::{AssetSource, Result, SharedString};
-use rust_embed::RustEmbed;
-
-#[derive(RustEmbed)]
-#[folder = "../../assets"]
-#[include = "fonts/**/*"]
-#[include = "icons/**/*"]
-#[include = "themes/**/*"]
-#[exclude = "themes/src/*"]
-#[include = "sounds/**/*"]
-#[include = "*.md"]
-#[exclude = "*.DS_Store"]
-pub struct Assets;
-
-impl AssetSource for Assets {
- fn load(&self, path: &str) -> Result<std::borrow::Cow<[u8]>> {
- Self::get(path)
- .map(|f| f.data)
- .ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
- }
-
- fn list(&self, path: &str) -> Result<Vec<SharedString>> {
- Ok(Self::iter()
- .filter_map(|p| {
- if p.starts_with(path) {
- Some(p.into())
- } else {
- None
- }
- })
- .collect())
- }
-}
@@ -1,299 +0,0 @@
-use anyhow::Context;
-use gpui::AppContext;
-pub use language::*;
-use node_runtime::NodeRuntime;
-use rust_embed::RustEmbed;
-use settings::Settings;
-use std::{borrow::Cow, str, sync::Arc};
-use util::{asset_str, paths::PLUGINS_DIR};
-
-use self::elixir::ElixirSettings;
-
-mod c;
-mod css;
-mod elixir;
-mod go;
-mod html;
-mod json;
-#[cfg(feature = "plugin_runtime")]
-mod language_plugin;
-mod lua;
-mod nu;
-mod php;
-mod python;
-mod ruby;
-mod rust;
-mod svelte;
-mod tailwind;
-mod typescript;
-mod uiua;
-mod vue;
-mod yaml;
-
-// 1. Add tree-sitter-{language} parser to zed crate
-// 2. Create a language directory in zed/crates/zed/src/languages and add the language to init function below
-// 3. Add config.toml to the newly created language directory using existing languages as a template
-// 4. Copy highlights from tree sitter repo for the language into a highlights.scm file.
-// Note: github highlights take the last match while zed takes the first
-// 5. Add indents.scm, outline.scm, and brackets.scm to implement indent on newline, outline/breadcrumbs,
-// and autoclosing brackets respectively
-// 6. If the language has injections add an injections.scm query file
-
-#[derive(RustEmbed)]
-#[folder = "src/languages"]
-#[exclude = "*.rs"]
-struct LanguageDir;
-
-pub fn init(
- languages: Arc<LanguageRegistry>,
- node_runtime: Arc<dyn NodeRuntime>,
- cx: &mut AppContext,
-) {
- ElixirSettings::register(cx);
-
- let language = |name, grammar, adapters| {
- languages.register(name, load_config(name), grammar, adapters, load_queries)
- };
-
- language("bash", tree_sitter_bash::language(), vec![]);
- language(
- "c",
- tree_sitter_c::language(),
- vec![Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>],
- );
- language(
- "cpp",
- tree_sitter_cpp::language(),
- vec![Arc::new(c::CLspAdapter)],
- );
- language(
- "css",
- tree_sitter_css::language(),
- vec![
- Arc::new(css::CssLspAdapter::new(node_runtime.clone())),
- Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
- ],
- );
-
- match &ElixirSettings::get(None, cx).lsp {
- elixir::ElixirLspSetting::ElixirLs => language(
- "elixir",
- tree_sitter_elixir::language(),
- vec![
- Arc::new(elixir::ElixirLspAdapter),
- Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
- ],
- ),
- elixir::ElixirLspSetting::NextLs => language(
- "elixir",
- tree_sitter_elixir::language(),
- vec![Arc::new(elixir::NextLspAdapter)],
- ),
- elixir::ElixirLspSetting::Local { path, arguments } => language(
- "elixir",
- tree_sitter_elixir::language(),
- vec![Arc::new(elixir::LocalLspAdapter {
- path: path.clone(),
- arguments: arguments.clone(),
- })],
- ),
- }
-
- language(
- "go",
- tree_sitter_go::language(),
- vec![Arc::new(go::GoLspAdapter)],
- );
- language(
- "heex",
- tree_sitter_heex::language(),
- vec![
- Arc::new(elixir::ElixirLspAdapter),
- Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
- ],
- );
- language(
- "json",
- tree_sitter_json::language(),
- vec![Arc::new(json::JsonLspAdapter::new(
- node_runtime.clone(),
- languages.clone(),
- ))],
- );
- language("markdown", tree_sitter_markdown::language(), vec![]);
- language(
- "python",
- tree_sitter_python::language(),
- vec![Arc::new(python::PythonLspAdapter::new(
- node_runtime.clone(),
- ))],
- );
- language(
- "rust",
- tree_sitter_rust::language(),
- vec![Arc::new(rust::RustLspAdapter)],
- );
- language("toml", tree_sitter_toml::language(), vec![]);
- language(
- "tsx",
- tree_sitter_typescript::language_tsx(),
- vec![
- Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
- Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
- Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
- ],
- );
- language(
- "typescript",
- tree_sitter_typescript::language_typescript(),
- vec![
- Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
- Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
- ],
- );
- language(
- "javascript",
- tree_sitter_typescript::language_tsx(),
- vec![
- Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
- Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
- Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
- ],
- );
- language(
- "html",
- tree_sitter_html::language(),
- vec![
- Arc::new(html::HtmlLspAdapter::new(node_runtime.clone())),
- Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
- ],
- );
- language(
- "ruby",
- tree_sitter_ruby::language(),
- vec![Arc::new(ruby::RubyLanguageServer)],
- );
- language(
- "erb",
- tree_sitter_embedded_template::language(),
- vec![
- Arc::new(ruby::RubyLanguageServer),
- Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
- ],
- );
- language("scheme", tree_sitter_scheme::language(), vec![]);
- language("racket", tree_sitter_racket::language(), vec![]);
- language(
- "lua",
- tree_sitter_lua::language(),
- vec![Arc::new(lua::LuaLspAdapter)],
- );
- language(
- "yaml",
- tree_sitter_yaml::language(),
- vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))],
- );
- language(
- "svelte",
- tree_sitter_svelte::language(),
- vec![
- Arc::new(svelte::SvelteLspAdapter::new(node_runtime.clone())),
- Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
- ],
- );
- language(
- "php",
- tree_sitter_php::language(),
- vec![
- Arc::new(php::IntelephenseLspAdapter::new(node_runtime.clone())),
- Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
- ],
- );
-
- language("elm", tree_sitter_elm::language(), vec![]);
- language("glsl", tree_sitter_glsl::language(), vec![]);
- language("nix", tree_sitter_nix::language(), vec![]);
- language(
- "nu",
- tree_sitter_nu::language(),
- vec![Arc::new(nu::NuLanguageServer {})],
- );
- language(
- "vue",
- tree_sitter_vue::language(),
- vec![Arc::new(vue::VueLspAdapter::new(node_runtime))],
- );
- language(
- "uiua",
- tree_sitter_uiua::language(),
- vec![Arc::new(uiua::UiuaLanguageServer {})],
- );
-
- if let Ok(children) = std::fs::read_dir(&*PLUGINS_DIR) {
- for child in children {
- if let Ok(child) = child {
- let path = child.path();
- let config_path = path.join("config.toml");
- if let Ok(config) = std::fs::read(&config_path) {
- let config: LanguageConfig = toml::from_slice(&config).unwrap();
- if let Some(grammar_name) = config.grammar_name.clone() {
- languages.register_wasm(path.into(), grammar_name, config);
- }
- }
- }
- }
- }
-}
-
-#[cfg(any(test, feature = "test-support"))]
-pub async fn language(
- name: &str,
- grammar: tree_sitter::Language,
- lsp_adapter: Option<Arc<dyn LspAdapter>>,
-) -> Arc<Language> {
- Arc::new(
- Language::new(load_config(name), Some(grammar))
- .with_lsp_adapters(lsp_adapter.into_iter().collect())
- .await
- .with_queries(load_queries(name))
- .unwrap(),
- )
-}
-
-fn load_config(name: &str) -> LanguageConfig {
- toml::from_slice(
- &LanguageDir::get(&format!("{}/config.toml", name))
- .unwrap()
- .data,
- )
- .with_context(|| format!("failed to load config.toml for language {name:?}"))
- .unwrap()
-}
-
-fn load_queries(name: &str) -> LanguageQueries {
- LanguageQueries {
- highlights: load_query(name, "/highlights"),
- brackets: load_query(name, "/brackets"),
- indents: load_query(name, "/indents"),
- outline: load_query(name, "/outline"),
- embedding: load_query(name, "/embedding"),
- injections: load_query(name, "/injections"),
- overrides: load_query(name, "/overrides"),
- }
-}
-
-fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
- let mut result = None;
- for path in LanguageDir::iter() {
- if let Some(remainder) = path.strip_prefix(name) {
- if remainder.starts_with(filename_prefix) {
- let contents = asset_str::<LanguageDir>(path.as_ref());
- match &mut result {
- None => result = Some(contents),
- Some(r) => r.to_mut().push_str(contents.as_ref()),
- }
- }
- }
- }
- result
-}
@@ -1,3 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
@@ -1,9 +0,0 @@
-name = "Shell Script"
-path_suffixes = ["sh", "bash", "bashrc", "bash_profile", "bash_aliases", "bash_logout", "profile", "zsh", "zshrc", "zshenv", "zsh_profile", "zsh_aliases", "zsh_histfile", "zlogin", "zprofile"]
-line_comment = "# "
-first_line_pattern = "^#!.*\\b(?:ba|z)?sh\\b"
-brackets = [
- { start = "[", end = "]", close = true, newline = false },
- { start = "(", end = ")", close = true, newline = false },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
-]
@@ -1,59 +0,0 @@
-[
- (string)
- (raw_string)
- (heredoc_body)
- (heredoc_start)
- (ansi_c_string)
-] @string
-
-(command_name) @function
-
-(variable_name) @property
-
-[
- "case"
- "do"
- "done"
- "elif"
- "else"
- "esac"
- "export"
- "fi"
- "for"
- "function"
- "if"
- "in"
- "select"
- "then"
- "unset"
- "until"
- "while"
- "local"
- "declare"
-] @keyword
-
-(comment) @comment
-
-(function_definition name: (word) @function)
-
-(file_descriptor) @number
-
-[
- (command_substitution)
- (process_substitution)
- (expansion)
-]@embedded
-
-[
- "$"
- "&&"
- ">"
- ">>"
- "<"
- "|"
-] @operator
-
-(
- (command (_) @constant)
- (#match? @constant "^-")
-)
@@ -1,321 +0,0 @@
-use anyhow::{anyhow, Context, Result};
-use async_trait::async_trait;
-use futures::StreamExt;
-pub use language::*;
-use lsp::LanguageServerBinary;
-use smol::fs::{self, File};
-use std::{any::Any, path::PathBuf, sync::Arc};
-use util::{
- fs::remove_matching,
- github::{latest_github_release, GitHubLspBinaryVersion},
- ResultExt,
-};
-
-pub struct CLspAdapter;
-
-#[async_trait]
-impl super::LspAdapter for CLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("clangd".into())
- }
-
- fn short_name(&self) -> &'static str {
- "clangd"
- }
-
- async fn fetch_latest_server_version(
- &self,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- let release = latest_github_release("clangd/clangd", false, delegate.http_client()).await?;
- let asset_name = format!("clangd-mac-{}.zip", release.name);
- let asset = release
- .assets
- .iter()
- .find(|asset| asset.name == asset_name)
- .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?;
- let version = GitHubLspBinaryVersion {
- name: release.name,
- url: asset.browser_download_url.clone(),
- };
- Ok(Box::new(version) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
- let zip_path = container_dir.join(format!("clangd_{}.zip", version.name));
- let version_dir = container_dir.join(format!("clangd_{}", version.name));
- let binary_path = version_dir.join("bin/clangd");
-
- if fs::metadata(&binary_path).await.is_err() {
- let mut response = delegate
- .http_client()
- .get(&version.url, Default::default(), true)
- .await
- .context("error downloading release")?;
- let mut file = File::create(&zip_path).await?;
- if !response.status().is_success() {
- Err(anyhow!(
- "download failed with status {}",
- response.status().to_string()
- ))?;
- }
- futures::io::copy(response.body_mut(), &mut file).await?;
-
- let unzip_status = smol::process::Command::new("unzip")
- .current_dir(&container_dir)
- .arg(&zip_path)
- .output()
- .await?
- .status;
- if !unzip_status.success() {
- Err(anyhow!("failed to unzip clangd archive"))?;
- }
-
- remove_matching(&container_dir, |entry| entry != version_dir).await;
- }
-
- Ok(LanguageServerBinary {
- path: binary_path,
- arguments: vec![],
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir)
- .await
- .map(|mut binary| {
- binary.arguments = vec!["--help".into()];
- binary
- })
- }
-
- async fn label_for_completion(
- &self,
- completion: &lsp::CompletionItem,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- let label = completion
- .label
- .strip_prefix('•')
- .unwrap_or(&completion.label)
- .trim();
-
- match completion.kind {
- Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => {
- let detail = completion.detail.as_ref().unwrap();
- let text = format!("{} {}", detail, label);
- let source = Rope::from(format!("struct S {{ {} }}", text).as_str());
- let runs = language.highlight_text(&source, 11..11 + text.len());
- return Some(CodeLabel {
- filter_range: detail.len() + 1..text.len(),
- text,
- runs,
- });
- }
- Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE)
- if completion.detail.is_some() =>
- {
- let detail = completion.detail.as_ref().unwrap();
- let text = format!("{} {}", detail, label);
- let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len());
- return Some(CodeLabel {
- filter_range: detail.len() + 1..text.len(),
- text,
- runs,
- });
- }
- Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD)
- if completion.detail.is_some() =>
- {
- let detail = completion.detail.as_ref().unwrap();
- let text = format!("{} {}", detail, label);
- let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len());
- return Some(CodeLabel {
- filter_range: detail.len() + 1..text.rfind('(').unwrap_or(text.len()),
- text,
- runs,
- });
- }
- Some(kind) => {
- let highlight_name = match kind {
- lsp::CompletionItemKind::STRUCT
- | lsp::CompletionItemKind::INTERFACE
- | lsp::CompletionItemKind::CLASS
- | lsp::CompletionItemKind::ENUM => Some("type"),
- lsp::CompletionItemKind::ENUM_MEMBER => Some("variant"),
- lsp::CompletionItemKind::KEYWORD => Some("keyword"),
- lsp::CompletionItemKind::VALUE | lsp::CompletionItemKind::CONSTANT => {
- Some("constant")
- }
- _ => None,
- };
- if let Some(highlight_id) = language
- .grammar()
- .and_then(|g| g.highlight_id_for_name(highlight_name?))
- {
- let mut label = CodeLabel::plain(label.to_string(), None);
- label.runs.push((
- 0..label.text.rfind('(').unwrap_or(label.text.len()),
- highlight_id,
- ));
- return Some(label);
- }
- }
- _ => {}
- }
- Some(CodeLabel::plain(label.to_string(), None))
- }
-
- async fn label_for_symbol(
- &self,
- name: &str,
- kind: lsp::SymbolKind,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- let (text, filter_range, display_range) = match kind {
- lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
- let text = format!("void {} () {{}}", name);
- let filter_range = 0..name.len();
- let display_range = 5..5 + name.len();
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::STRUCT => {
- let text = format!("struct {} {{}}", name);
- let filter_range = 7..7 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::ENUM => {
- let text = format!("enum {} {{}}", name);
- let filter_range = 5..5 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::INTERFACE | lsp::SymbolKind::CLASS => {
- let text = format!("class {} {{}}", name);
- let filter_range = 6..6 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::CONSTANT => {
- let text = format!("const int {} = 0;", name);
- let filter_range = 10..10 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::MODULE => {
- let text = format!("namespace {} {{}}", name);
- let filter_range = 10..10 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::TYPE_PARAMETER => {
- let text = format!("typename {} {{}};", name);
- let filter_range = 9..9 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- _ => return None,
- };
-
- Some(CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
- filter_range,
- })
- }
-}
-
-async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last_clangd_dir = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_dir() {
- last_clangd_dir = Some(entry.path());
- }
- }
- let clangd_dir = last_clangd_dir.ok_or_else(|| anyhow!("no cached binary"))?;
- let clangd_bin = clangd_dir.join("bin/clangd");
- if clangd_bin.exists() {
- Ok(LanguageServerBinary {
- path: clangd_bin,
- arguments: vec![],
- })
- } else {
- Err(anyhow!(
- "missing clangd binary in directory {:?}",
- clangd_dir
- ))
- }
- })()
- .await
- .log_err()
-}
-
-#[cfg(test)]
-mod tests {
- use gpui::{Context, TestAppContext};
- use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer};
- use settings::SettingsStore;
- use std::num::NonZeroU32;
-
- #[gpui::test]
- async fn test_c_autoindent(cx: &mut TestAppContext) {
- // cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX);
- cx.update(|cx| {
- let test_settings = SettingsStore::test(cx);
- cx.set_global(test_settings);
- language::init(cx);
- cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<AllLanguageSettings>(cx, |s| {
- s.defaults.tab_size = NonZeroU32::new(2);
- });
- });
- });
- let language = crate::languages::language("c", tree_sitter_c::language(), None).await;
-
- cx.new_model(|cx| {
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), "").with_language(language, cx);
-
- // empty function
- buffer.edit([(0..0, "int main() {}")], None, cx);
-
- // indent inside braces
- let ix = buffer.len() - 1;
- buffer.edit([(ix..ix, "\n\n")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(buffer.text(), "int main() {\n \n}");
-
- // indent body of single-statement if statement
- let ix = buffer.len() - 2;
- buffer.edit([(ix..ix, "if (a)\nb;")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(buffer.text(), "int main() {\n if (a)\n b;\n}");
-
- // indent inside field expression
- let ix = buffer.len() - 3;
- buffer.edit([(ix..ix, "\n.c")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(buffer.text(), "int main() {\n if (a)\n b\n .c;\n}");
-
- buffer
- });
- }
-}
@@ -1,3 +0,0 @@
-("[" @open "]" @close)
-("{" @open "}" @close)
-("\"" @open "\"" @close)
@@ -1,12 +0,0 @@
-name = "C"
-path_suffixes = ["c"]
-line_comment = "// "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
- { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
-]
@@ -1,43 +0,0 @@
-(
- (comment)* @context
- .
- (declaration
- declarator: [
- (function_declarator
- declarator: (_) @name)
- (pointer_declarator
- "*" @name
- declarator: (function_declarator
- declarator: (_) @name))
- (pointer_declarator
- "*" @name
- declarator: (pointer_declarator
- "*" @name
- declarator: (function_declarator
- declarator: (_) @name)))
- ]
- ) @item
- )
-
-(
- (comment)* @context
- .
- (function_definition
- declarator: [
- (function_declarator
- declarator: (_) @name
- )
- (pointer_declarator
- "*" @name
- declarator: (function_declarator
- declarator: (_) @name
- ))
- (pointer_declarator
- "*" @name
- declarator: (pointer_declarator
- "*" @name
- declarator: (function_declarator
- declarator: (_) @name)))
- ]
- ) @item
- )
@@ -1,109 +0,0 @@
-[
- "break"
- "case"
- "const"
- "continue"
- "default"
- "do"
- "else"
- "enum"
- "extern"
- "for"
- "if"
- "inline"
- "return"
- "sizeof"
- "static"
- "struct"
- "switch"
- "typedef"
- "union"
- "volatile"
- "while"
-] @keyword
-
-[
- "#define"
- "#elif"
- "#else"
- "#endif"
- "#if"
- "#ifdef"
- "#ifndef"
- "#include"
- (preproc_directive)
-] @keyword
-
-[
- "--"
- "-"
- "-="
- "->"
- "="
- "!="
- "*"
- "&"
- "&&"
- "+"
- "++"
- "+="
- "<"
- "=="
- ">"
- "||"
-] @operator
-
-[
- "."
- ";"
-] @punctuation.delimiter
-
-[
- "{"
- "}"
- "("
- ")"
- "["
- "]"
-] @punctuation.bracket
-
-[
- (string_literal)
- (system_lib_string)
- (char_literal)
-] @string
-
-(comment) @comment
-
-(number_literal) @number
-
-[
- (true)
- (false)
- (null)
-] @constant
-
-(identifier) @variable
-
-((identifier) @constant
- (#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
-
-(call_expression
- function: (identifier) @function)
-(call_expression
- function: (field_expression
- field: (field_identifier) @function))
-(function_declarator
- declarator: (identifier) @function)
-(preproc_function_def
- name: (identifier) @function.special)
-
-(field_identifier) @property
-(statement_identifier) @label
-
-[
- (type_identifier)
- (primitive_type)
- (sized_type_specifier)
-] @type
-
@@ -1,9 +0,0 @@
-[
- (field_expression)
- (assignment_expression)
- (if_statement)
- (for_statement)
-] @indent
-
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,7 +0,0 @@
-(preproc_def
- value: (preproc_arg) @content
- (#set! "language" "c"))
-
-(preproc_function_def
- value: (preproc_arg) @content
- (#set! "language" "c"))
@@ -1,70 +0,0 @@
-(preproc_def
- "#define" @context
- name: (_) @name) @item
-
-(preproc_function_def
- "#define" @context
- name: (_) @name
- parameters: (preproc_params
- "(" @context
- ")" @context)) @item
-
-(type_definition
- "typedef" @context
- declarator: (_) @name) @item
-
-(declaration
- (type_qualifier)? @context
- type: (_)? @context
- declarator: [
- (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))
- (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)))
- (pointer_declarator
- "*" @context
- declarator: (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))))
- ]
-) @item
-
-(function_definition
- (type_qualifier)? @context
- type: (_)? @context
- declarator: [
- (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))
- (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)))
- (pointer_declarator
- "*" @context
- declarator: (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))))
- ]
-) @item
@@ -1,2 +0,0 @@
-(comment) @comment
-(string_literal) @string
@@ -1,3 +0,0 @@
-("[" @open "]" @close)
-("{" @open "}" @close)
-("\"" @open "\"" @close)
@@ -1,12 +0,0 @@
-name = "C++"
-path_suffixes = ["cc", "cpp", "h", "hpp", "cxx", "hxx", "inl"]
-line_comment = "// "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
- { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
-]
@@ -1,61 +0,0 @@
-(
- (comment)* @context
- .
- (function_definition
- (type_qualifier)? @name
- type: (_)? @name
- declarator: [
- (function_declarator
- declarator: (_) @name)
- (pointer_declarator
- "*" @name
- declarator: (function_declarator
- declarator: (_) @name))
- (pointer_declarator
- "*" @name
- declarator: (pointer_declarator
- "*" @name
- declarator: (function_declarator
- declarator: (_) @name)))
- (reference_declarator
- ["&" "&&"] @name
- (function_declarator
- declarator: (_) @name))
- ]
- (type_qualifier)? @name) @item
- )
-
-(
- (comment)* @context
- .
- (template_declaration
- (class_specifier
- "class" @name
- name: (_) @name)
- ) @item
-)
-
-(
- (comment)* @context
- .
- (class_specifier
- "class" @name
- name: (_) @name) @item
- )
-
-(
- (comment)* @context
- .
- (enum_specifier
- "enum" @name
- name: (_) @name) @item
- )
-
-(
- (comment)* @context
- .
- (declaration
- type: (struct_specifier
- "struct" @name)
- declarator: (_) @name) @item
-)
@@ -1,158 +0,0 @@
-(identifier) @variable
-
-(call_expression
- function: (qualified_identifier
- name: (identifier) @function))
-
-(call_expression
- function: (identifier) @function)
-
-(call_expression
- function: (field_expression
- field: (field_identifier) @function))
-
-(preproc_function_def
- name: (identifier) @function.special)
-
-(template_function
- name: (identifier) @function)
-
-(template_method
- name: (field_identifier) @function)
-
-(function_declarator
- declarator: (identifier) @function)
-
-(function_declarator
- declarator: (qualified_identifier
- name: (identifier) @function))
-
-(function_declarator
- declarator: (field_identifier) @function)
-
-((namespace_identifier) @type
- (#match? @type "^[A-Z]"))
-
-(auto) @type
-(type_identifier) @type
-
-((identifier) @constant
- (#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
-
-(field_identifier) @property
-(statement_identifier) @label
-(this) @variable.special
-
-[
- "break"
- "case"
- "catch"
- "class"
- "co_await"
- "co_return"
- "co_yield"
- "const"
- "constexpr"
- "continue"
- "default"
- "delete"
- "do"
- "else"
- "enum"
- "explicit"
- "extern"
- "final"
- "for"
- "friend"
- "if"
- "if"
- "inline"
- "mutable"
- "namespace"
- "new"
- "noexcept"
- "override"
- "private"
- "protected"
- "public"
- "return"
- "sizeof"
- "static"
- "struct"
- "switch"
- "template"
- "throw"
- "try"
- "typedef"
- "typename"
- "union"
- "using"
- "virtual"
- "volatile"
- "while"
- (primitive_type)
- (type_qualifier)
-] @keyword
-
-[
- "#define"
- "#elif"
- "#else"
- "#endif"
- "#if"
- "#ifdef"
- "#ifndef"
- "#include"
- (preproc_directive)
-] @keyword
-
-(comment) @comment
-
-[
- (true)
- (false)
- (null)
- (nullptr)
-] @constant
-
-(number_literal) @number
-
-[
- (string_literal)
- (system_lib_string)
- (char_literal)
- (raw_string_literal)
-] @string
-
-[
- "."
- ";"
-] @punctuation.delimiter
-
-[
- "{"
- "}"
- "("
- ")"
- "["
- "]"
-] @punctuation.bracket
-
-[
- "--"
- "-"
- "-="
- "->"
- "="
- "!="
- "*"
- "&"
- "&&"
- "+"
- "++"
- "+="
- "<"
- "=="
- ">"
- "||"
-] @operator
@@ -1,7 +0,0 @@
-[
- (field_expression)
- (assignment_expression)
-] @indent
-
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,7 +0,0 @@
-(preproc_def
- value: (preproc_arg) @content
- (#set! "language" "c++"))
-
-(preproc_function_def
- value: (preproc_arg) @content
- (#set! "language" "c++"))
@@ -1,149 +0,0 @@
-(preproc_def
- "#define" @context
- name: (_) @name) @item
-
-(preproc_function_def
- "#define" @context
- name: (_) @name
- parameters: (preproc_params
- "(" @context
- ")" @context)) @item
-
-(type_definition
- "typedef" @context
- declarator: (_) @name) @item
-
-(struct_specifier
- "struct" @context
- name: (_) @name) @item
-
-(class_specifier
- "class" @context
- name: (_) @name) @item
-
-(enum_specifier
- "enum" @context
- name: (_) @name) @item
-
-(enumerator
- name: (_) @name) @item
-
-(declaration
- (storage_class_specifier) @context
- (type_qualifier)? @context
- type: (_) @context
- declarator: (init_declarator
- declarator: (_) @name)) @item
-
-(function_definition
- (type_qualifier)? @context
- type: (_)? @context
- declarator: [
- (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))
- (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)))
- (pointer_declarator
- "*" @context
- declarator: (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))))
- (reference_declarator
- ["&" "&&"] @context
- (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)))
- ]
- (type_qualifier)? @context) @item
-
-(declaration
- (type_qualifier)? @context
- type: (_)? @context
- declarator: [
- (field_identifier) @name
- (pointer_declarator
- "*" @context
- declarator: (field_identifier) @name)
- (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))
- (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)))
- (pointer_declarator
- "*" @context
- declarator: (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))))
- (reference_declarator
- ["&" "&&"] @context
- (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)))
- ]
- (type_qualifier)? @context) @item
-
-(field_declaration
- (type_qualifier)? @context
- type: (_) @context
- declarator: [
- (field_identifier) @name
- (pointer_declarator
- "*" @context
- declarator: (field_identifier) @name)
- (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))
- (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)))
- (pointer_declarator
- "*" @context
- declarator: (pointer_declarator
- "*" @context
- declarator: (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context))))
- (reference_declarator
- ["&" "&&"] @context
- (function_declarator
- declarator: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)))
- ]
- (type_qualifier)? @context) @item
@@ -1,2 +0,0 @@
-(comment) @comment
-(string_literal) @string
@@ -1,130 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use futures::StreamExt;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use node_runtime::NodeRuntime;
-use serde_json::json;
-use smol::fs;
-use std::{
- any::Any,
- ffi::OsString,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::ResultExt;
-
-const SERVER_PATH: &'static str =
- "node_modules/vscode-langservers-extracted/bin/vscode-css-language-server";
-
-fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-pub struct CssLspAdapter {
- node: Arc<dyn NodeRuntime>,
-}
-
-impl CssLspAdapter {
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- CssLspAdapter { node }
- }
-}
-
-#[async_trait]
-impl LspAdapter for CssLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("vscode-css-language-server".into())
- }
-
- fn short_name(&self) -> &'static str {
- "css"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Any + Send>> {
- Ok(Box::new(
- self.node
- .npm_package_latest_version("vscode-langservers-extracted")
- .await?,
- ) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<String>().unwrap();
- let server_path = container_dir.join(SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(
- &container_dir,
- &[("vscode-langservers-extracted", version.as_str())],
- )
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn initialization_options(&self) -> Option<serde_json::Value> {
- Some(json!({
- "provideFormatter": true
- }))
- }
-}
-
-async fn get_cached_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last_version_dir = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_dir() {
- last_version_dir = Some(entry.path());
- }
- }
- let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
- let server_path = last_version_dir.join(SERVER_PATH);
- if server_path.exists() {
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- } else {
- Err(anyhow!(
- "missing executable in directory {:?}",
- last_version_dir
- ))
- }
- })()
- .await
- .log_err()
-}
@@ -1,3 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
@@ -1,13 +0,0 @@
-name = "CSS"
-path_suffixes = ["css"]
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string", "comment"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
-]
-word_characters = ["-"]
-block_comment = ["/* ", " */"]
-prettier_parser_name = "css"
@@ -1,78 +0,0 @@
-(comment) @comment
-
-[
- (tag_name)
- (nesting_selector)
- (universal_selector)
-] @tag
-
-[
- "~"
- ">"
- "+"
- "-"
- "*"
- "/"
- "="
- "^="
- "|="
- "~="
- "$="
- "*="
- "and"
- "or"
- "not"
- "only"
-] @operator
-
-(attribute_selector (plain_value) @string)
-
-(attribute_name) @attribute
-(pseudo_element_selector (tag_name) @attribute)
-(pseudo_class_selector (class_name) @attribute)
-
-[
- (class_name)
- (id_name)
- (namespace_name)
- (property_name)
- (feature_name)
-] @property
-
-(function_name) @function
-
-(
- [
- (property_name)
- (plain_value)
- ] @variable.special
- (#match? @variable.special "^--")
-)
-
-[
- "@media"
- "@import"
- "@charset"
- "@namespace"
- "@supports"
- "@keyframes"
- (at_keyword)
- (to)
- (from)
- (important)
-] @keyword
-
-(string_value) @string
-(color_value) @string.special
-
-[
- (integer_value)
- (float_value)
-] @number
-
-(unit) @type
-
-[
- ","
- ":"
-] @punctuation.delimiter
@@ -1 +0,0 @@
-(_ "{" "}" @end) @indent
@@ -1,2 +0,0 @@
-(comment) @comment
-(string_value) @string
@@ -1,542 +0,0 @@
-use anyhow::{anyhow, bail, Context, Result};
-use async_trait::async_trait;
-use futures::StreamExt;
-use gpui::{AsyncAppContext, Task};
-pub use language::*;
-use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind};
-use schemars::JsonSchema;
-use serde_derive::{Deserialize, Serialize};
-use settings::Settings;
-use smol::fs::{self, File};
-use std::{
- any::Any,
- env::consts,
- ops::Deref,
- path::PathBuf,
- sync::{
- atomic::{AtomicBool, Ordering::SeqCst},
- Arc,
- },
-};
-use util::{
- async_maybe,
- fs::remove_matching,
- github::{latest_github_release, GitHubLspBinaryVersion},
- ResultExt,
-};
-
-#[derive(Clone, Serialize, Deserialize, JsonSchema)]
-pub struct ElixirSettings {
- pub lsp: ElixirLspSetting,
-}
-
-#[derive(Clone, Serialize, Deserialize, JsonSchema)]
-#[serde(rename_all = "snake_case")]
-pub enum ElixirLspSetting {
- ElixirLs,
- NextLs,
- Local {
- path: String,
- arguments: Vec<String>,
- },
-}
-
-#[derive(Clone, Serialize, Default, Deserialize, JsonSchema)]
-pub struct ElixirSettingsContent {
- lsp: Option<ElixirLspSetting>,
-}
-
-impl Settings for ElixirSettings {
- const KEY: Option<&'static str> = Some("elixir");
-
- type FileContent = ElixirSettingsContent;
-
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut gpui::AppContext,
- ) -> Result<Self>
- where
- Self: Sized,
- {
- Self::load_via_json_merge(default_value, user_values)
- }
-}
-
-pub struct ElixirLspAdapter;
-
-#[async_trait]
-impl LspAdapter for ElixirLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("elixir-ls".into())
- }
-
- fn short_name(&self) -> &'static str {
- "elixir-ls"
- }
-
- fn will_start_server(
- &self,
- delegate: &Arc<dyn LspAdapterDelegate>,
- cx: &mut AsyncAppContext,
- ) -> Option<Task<Result<()>>> {
- static DID_SHOW_NOTIFICATION: AtomicBool = AtomicBool::new(false);
-
- const NOTIFICATION_MESSAGE: &str = "Could not run the elixir language server, `elixir-ls`, because `elixir` was not found.";
-
- let delegate = delegate.clone();
- Some(cx.spawn(|cx| async move {
- let elixir_output = smol::process::Command::new("elixir")
- .args(["--version"])
- .output()
- .await;
- if elixir_output.is_err() {
- if DID_SHOW_NOTIFICATION
- .compare_exchange(false, true, SeqCst, SeqCst)
- .is_ok()
- {
- cx.update(|cx| {
- delegate.show_notification(NOTIFICATION_MESSAGE, cx);
- })?
- }
- return Err(anyhow!("cannot run elixir-ls"));
- }
-
- Ok(())
- }))
- }
-
- async fn fetch_latest_server_version(
- &self,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- let http = delegate.http_client();
- let release = latest_github_release("elixir-lsp/elixir-ls", false, http).await?;
- let version_name = release
- .name
- .strip_prefix("Release ")
- .context("Elixir-ls release name does not start with prefix")?
- .to_owned();
-
- let asset_name = format!("elixir-ls-{}.zip", &version_name);
- let asset = release
- .assets
- .iter()
- .find(|asset| asset.name == asset_name)
- .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?;
-
- let version = GitHubLspBinaryVersion {
- name: version_name,
- url: asset.browser_download_url.clone(),
- };
- Ok(Box::new(version) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
- let zip_path = container_dir.join(format!("elixir-ls_{}.zip", version.name));
- let folder_path = container_dir.join("elixir-ls");
- let binary_path = folder_path.join("language_server.sh");
-
- if fs::metadata(&binary_path).await.is_err() {
- let mut response = delegate
- .http_client()
- .get(&version.url, Default::default(), true)
- .await
- .context("error downloading release")?;
- let mut file = File::create(&zip_path)
- .await
- .with_context(|| format!("failed to create file {}", zip_path.display()))?;
- if !response.status().is_success() {
- Err(anyhow!(
- "download failed with status {}",
- response.status().to_string()
- ))?;
- }
- futures::io::copy(response.body_mut(), &mut file).await?;
-
- fs::create_dir_all(&folder_path)
- .await
- .with_context(|| format!("failed to create directory {}", folder_path.display()))?;
- let unzip_status = smol::process::Command::new("unzip")
- .arg(&zip_path)
- .arg("-d")
- .arg(&folder_path)
- .output()
- .await?
- .status;
- if !unzip_status.success() {
- Err(anyhow!("failed to unzip elixir-ls archive"))?;
- }
-
- remove_matching(&container_dir, |entry| entry != folder_path).await;
- }
-
- Ok(LanguageServerBinary {
- path: binary_path,
- arguments: vec![],
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary_elixir_ls(container_dir).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary_elixir_ls(container_dir).await
- }
-
- async fn label_for_completion(
- &self,
- completion: &lsp::CompletionItem,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- match completion.kind.zip(completion.detail.as_ref()) {
- Some((_, detail)) if detail.starts_with("(function)") => {
- let text = detail.strip_prefix("(function) ")?;
- let filter_range = 0..text.find('(').unwrap_or(text.len());
- let source = Rope::from(format!("def {text}").as_str());
- let runs = language.highlight_text(&source, 4..4 + text.len());
- return Some(CodeLabel {
- text: text.to_string(),
- runs,
- filter_range,
- });
- }
- Some((_, detail)) if detail.starts_with("(macro)") => {
- let text = detail.strip_prefix("(macro) ")?;
- let filter_range = 0..text.find('(').unwrap_or(text.len());
- let source = Rope::from(format!("defmacro {text}").as_str());
- let runs = language.highlight_text(&source, 9..9 + text.len());
- return Some(CodeLabel {
- text: text.to_string(),
- runs,
- filter_range,
- });
- }
- Some((
- CompletionItemKind::CLASS
- | CompletionItemKind::MODULE
- | CompletionItemKind::INTERFACE
- | CompletionItemKind::STRUCT,
- _,
- )) => {
- let filter_range = 0..completion
- .label
- .find(" (")
- .unwrap_or(completion.label.len());
- let text = &completion.label[filter_range.clone()];
- let source = Rope::from(format!("defmodule {text}").as_str());
- let runs = language.highlight_text(&source, 10..10 + text.len());
- return Some(CodeLabel {
- text: completion.label.clone(),
- runs,
- filter_range,
- });
- }
- _ => {}
- }
-
- None
- }
-
- async fn label_for_symbol(
- &self,
- name: &str,
- kind: SymbolKind,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- let (text, filter_range, display_range) = match kind {
- SymbolKind::METHOD | SymbolKind::FUNCTION => {
- let text = format!("def {}", name);
- let filter_range = 4..4 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- SymbolKind::CLASS | SymbolKind::MODULE | SymbolKind::INTERFACE | SymbolKind::STRUCT => {
- let text = format!("defmodule {}", name);
- let filter_range = 10..10 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- _ => return None,
- };
-
- Some(CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
- filter_range,
- })
- }
-}
-
-async fn get_cached_server_binary_elixir_ls(
- container_dir: PathBuf,
-) -> Option<LanguageServerBinary> {
- let server_path = container_dir.join("elixir-ls/language_server.sh");
- if server_path.exists() {
- Some(LanguageServerBinary {
- path: server_path,
- arguments: vec![],
- })
- } else {
- log::error!("missing executable in directory {:?}", server_path);
- None
- }
-}
-
-pub struct NextLspAdapter;
-
-#[async_trait]
-impl LspAdapter for NextLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("next-ls".into())
- }
-
- fn short_name(&self) -> &'static str {
- "next-ls"
- }
-
- async fn fetch_latest_server_version(
- &self,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- let release =
- latest_github_release("elixir-tools/next-ls", false, delegate.http_client()).await?;
- let version = release.name.clone();
- let platform = match consts::ARCH {
- "x86_64" => "darwin_amd64",
- "aarch64" => "darwin_arm64",
- other => bail!("Running on unsupported platform: {other}"),
- };
- let asset_name = format!("next_ls_{}", platform);
- let asset = release
- .assets
- .iter()
- .find(|asset| asset.name == asset_name)
- .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?;
- let version = GitHubLspBinaryVersion {
- name: version,
- url: asset.browser_download_url.clone(),
- };
- Ok(Box::new(version) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
-
- let binary_path = container_dir.join("next-ls");
-
- if fs::metadata(&binary_path).await.is_err() {
- let mut response = delegate
- .http_client()
- .get(&version.url, Default::default(), true)
- .await
- .map_err(|err| anyhow!("error downloading release: {}", err))?;
-
- let mut file = smol::fs::File::create(&binary_path).await?;
- if !response.status().is_success() {
- Err(anyhow!(
- "download failed with status {}",
- response.status().to_string()
- ))?;
- }
- futures::io::copy(response.body_mut(), &mut file).await?;
-
- fs::set_permissions(
- &binary_path,
- <fs::Permissions as fs::unix::PermissionsExt>::from_mode(0o755),
- )
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: binary_path,
- arguments: vec!["--stdio".into()],
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary_next(container_dir)
- .await
- .map(|mut binary| {
- binary.arguments = vec!["--stdio".into()];
- binary
- })
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary_next(container_dir)
- .await
- .map(|mut binary| {
- binary.arguments = vec!["--help".into()];
- binary
- })
- }
-
- async fn label_for_completion(
- &self,
- completion: &lsp::CompletionItem,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- label_for_completion_elixir(completion, language)
- }
-
- async fn label_for_symbol(
- &self,
- name: &str,
- symbol_kind: SymbolKind,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- label_for_symbol_elixir(name, symbol_kind, language)
- }
-}
-
-async fn get_cached_server_binary_next(container_dir: PathBuf) -> Option<LanguageServerBinary> {
- async_maybe!({
- let mut last_binary_path = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_file()
- && entry
- .file_name()
- .to_str()
- .map_or(false, |name| name == "next-ls")
- {
- last_binary_path = Some(entry.path());
- }
- }
-
- if let Some(path) = last_binary_path {
- Ok(LanguageServerBinary {
- path,
- arguments: Vec::new(),
- })
- } else {
- Err(anyhow!("no cached binary"))
- }
- })
- .await
- .log_err()
-}
-
-pub struct LocalLspAdapter {
- pub path: String,
- pub arguments: Vec<String>,
-}
-
-#[async_trait]
-impl LspAdapter for LocalLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("local-ls".into())
- }
-
- fn short_name(&self) -> &'static str {
- "local-ls"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- Ok(Box::new(()) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- _: Box<dyn 'static + Send + Any>,
- _: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let path = shellexpand::full(&self.path)?;
- Ok(LanguageServerBinary {
- path: PathBuf::from(path.deref()),
- arguments: self.arguments.iter().map(|arg| arg.into()).collect(),
- })
- }
-
- async fn cached_server_binary(
- &self,
- _: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- let path = shellexpand::full(&self.path).ok()?;
- Some(LanguageServerBinary {
- path: PathBuf::from(path.deref()),
- arguments: self.arguments.iter().map(|arg| arg.into()).collect(),
- })
- }
-
- async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
- let path = shellexpand::full(&self.path).ok()?;
- Some(LanguageServerBinary {
- path: PathBuf::from(path.deref()),
- arguments: self.arguments.iter().map(|arg| arg.into()).collect(),
- })
- }
-
- async fn label_for_completion(
- &self,
- completion: &lsp::CompletionItem,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- label_for_completion_elixir(completion, language)
- }
-
- async fn label_for_symbol(
- &self,
- name: &str,
- symbol: SymbolKind,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- label_for_symbol_elixir(name, symbol, language)
- }
-}
-
-fn label_for_completion_elixir(
- completion: &lsp::CompletionItem,
- language: &Arc<Language>,
-) -> Option<CodeLabel> {
- return Some(CodeLabel {
- runs: language.highlight_text(&completion.label.clone().into(), 0..completion.label.len()),
- text: completion.label.clone(),
- filter_range: 0..completion.label.len(),
- });
-}
-
-fn label_for_symbol_elixir(
- name: &str,
- _: SymbolKind,
- language: &Arc<Language>,
-) -> Option<CodeLabel> {
- Some(CodeLabel {
- runs: language.highlight_text(&name.into(), 0..name.len()),
- text: name.to_string(),
- filter_range: 0..name.len(),
- })
-}
@@ -1,5 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
-("\"" @open "\"" @close)
-("do" @open "end" @close)
@@ -1,16 +0,0 @@
-name = "Elixir"
-path_suffixes = ["ex", "exs"]
-line_comment = "# "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string", "comment"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
-]
-scope_opt_in_language_servers = ["tailwindcss-language-server"]
-
-[overrides.string]
-word_characters = ["-"]
-opt_into_language_servers = ["tailwindcss-language-server"]
@@ -1,27 +0,0 @@
-(
- (unary_operator
- operator: "@"
- operand: (call
- target: (identifier) @unary
- (#match? @unary "^(doc)$"))
- ) @context
- .
- (call
- target: (identifier) @name
- (arguments
- [
- (identifier) @name
- (call
- target: (identifier) @name)
- (binary_operator
- left: (call
- target: (identifier) @name)
- operator: "when")
- ])
- (#match? @name "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
- )
-
- (call
- target: (identifier) @name
- (arguments (alias) @name)
- (#match? @name "^(defmodule|defprotocol)$")) @item
@@ -1,153 +0,0 @@
-["when" "and" "or" "not" "in" "not in" "fn" "do" "end" "catch" "rescue" "after" "else"] @keyword
-
-(unary_operator
- operator: "&"
- operand: (integer) @operator)
-
-(operator_identifier) @operator
-
-(unary_operator
- operator: _ @operator)
-
-(binary_operator
- operator: _ @operator)
-
-(dot
- operator: _ @operator)
-
-(stab_clause
- operator: _ @operator)
-
-[
- (boolean)
- (nil)
-] @constant
-
-[
- (integer)
- (float)
-] @number
-
-(alias) @type
-
-(call
- target: (dot
- left: (atom) @type))
-
-(char) @constant
-
-(escape_sequence) @string.escape
-
-[
- (atom)
- (quoted_atom)
- (keyword)
- (quoted_keyword)
-] @string.special.symbol
-
-[
- (string)
- (charlist)
-] @string
-
-(sigil
- (sigil_name) @__name__
- quoted_start: _ @string
- quoted_end: _ @string
- (#match? @__name__ "^[sS]$")) @string
-
-(sigil
- (sigil_name) @__name__
- quoted_start: _ @string.regex
- quoted_end: _ @string.regex
- (#match? @__name__ "^[rR]$")) @string.regex
-
-(sigil
- (sigil_name) @__name__
- quoted_start: _ @string.special
- quoted_end: _ @string.special) @string.special
-
-(
- (identifier) @comment.unused
- (#match? @comment.unused "^_")
-)
-
-(call
- target: [
- (identifier) @function
- (dot
- right: (identifier) @function)
- ])
-
-(call
- target: (identifier) @keyword
- (arguments
- [
- (identifier) @function
- (binary_operator
- left: (identifier) @function
- operator: "when")
- (binary_operator
- operator: "|>"
- right: (identifier))
- ])
- (#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
-
-(binary_operator
- operator: "|>"
- right: (identifier) @function)
-
-(call
- target: (identifier) @keyword
- (#match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$"))
-
-(call
- target: (identifier) @keyword
- (#match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
-
-(
- (identifier) @constant.builtin
- (#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$")
-)
-
-(unary_operator
- operator: "@" @comment.doc
- operand: (call
- target: (identifier) @__attribute__ @comment.doc
- (arguments
- [
- (string)
- (charlist)
- (sigil)
- (boolean)
- ] @comment.doc))
- (#match? @__attribute__ "^(moduledoc|typedoc|doc)$"))
-
-(comment) @comment
-
-[
- "%"
-] @punctuation
-
-[
- ","
- ";"
-] @punctuation.delimiter
-
-[
- "("
- ")"
- "["
- "]"
- "{"
- "}"
- "<<"
- ">>"
-] @punctuation.bracket
-
-(interpolation "#{" @punctuation.special "}" @punctuation.special) @embedded
-
-((sigil
- (sigil_name) @_sigil_name
- (quoted_content) @embedded)
- (#eq? @_sigil_name "H"))
@@ -1,6 +0,0 @@
-(call) @indent
-
-(_ "[" "]" @end) @indent
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
-(_ "do" "end" @end) @indent
@@ -1,7 +0,0 @@
-; Phoenix HTML template
-
-((sigil
- (sigil_name) @_sigil_name
- (quoted_content) @content)
- (#eq? @_sigil_name "H")
- (#set! language "heex"))
@@ -1,26 +0,0 @@
-(call
- target: (identifier) @context
- (arguments (alias) @name)
- (#match? @context "^(defmodule|defprotocol)$")) @item
-
-(call
- target: (identifier) @context
- (arguments
- [
- (identifier) @name
- (call
- target: (identifier) @name
- (arguments
- "(" @context.extra
- _* @context.extra
- ")" @context.extra))
- (binary_operator
- left: (call
- target: (identifier) @name
- (arguments
- "(" @context.extra
- _* @context.extra
- ")" @context.extra))
- operator: "when")
- ])
- (#match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
@@ -1,2 +0,0 @@
-(comment) @comment
-[(string) (charlist)] @string
@@ -1,11 +0,0 @@
-name = "Elm"
-path_suffixes = ["elm"]
-line_comment = "-- "
-block_comment = ["{- ", " -}"]
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
-]
@@ -1,72 +0,0 @@
-[
- "if"
- "then"
- "else"
- "let"
- "in"
- (case)
- (of)
- (backslash)
- (as)
- (port)
- (exposing)
- (alias)
- (import)
- (module)
- (type)
- (arrow)
- ] @keyword
-
-[
- (eq)
- (operator_identifier)
- (colon)
-] @operator
-
-(type_annotation(lower_case_identifier) @function)
-(port_annotation(lower_case_identifier) @function)
-(function_declaration_left(lower_case_identifier) @function.definition)
-
-(function_call_expr
- target: (value_expr
- name: (value_qid (lower_case_identifier) @function)))
-
-(exposed_value(lower_case_identifier) @function)
-(exposed_type(upper_case_identifier) @type)
-
-(field_access_expr(value_expr(value_qid)) @identifier)
-(lower_pattern) @variable
-(record_base_identifier) @identifier
-
-[
- "("
- ")"
-] @punctuation.bracket
-
-[
- "|"
- ","
-] @punctuation.delimiter
-
-(number_constant_expr) @constant
-
-(type_declaration(upper_case_identifier) @type)
-(type_ref) @type
-(type_alias_declaration name: (upper_case_identifier) @type)
-
-(value_expr(upper_case_qid(upper_case_identifier)) @type)
-
-[
- (line_comment)
- (block_comment)
-] @comment
-
-(string_escape) @string.escape
-
-[
- (open_quote)
- (close_quote)
- (regular_string_part)
- (open_char)
- (close_char)
-] @string
@@ -1,2 +0,0 @@
-((glsl_content) @content
- (#set! "language" "glsl"))
@@ -1,22 +0,0 @@
-(type_declaration
- (type) @context
- (upper_case_identifier) @name) @item
-
-(type_alias_declaration
- (type) @context
- (alias) @context
- name: (upper_case_identifier) @name) @item
-
-(type_alias_declaration
- typeExpression:
- (type_expression
- part: (record_type
- (field_type
- name: (lower_case_identifier) @name) @item)))
-
-(union_variant
- name: (upper_case_identifier) @name) @item
-
-(value_declaration
- functionDeclarationLeft:
- (function_declaration_left(lower_case_identifier) @name)) @item
@@ -1,8 +0,0 @@
-name = "ERB"
-path_suffixes = ["erb"]
-autoclose_before = ">})"
-brackets = [
- { start = "<", end = ">", close = true, newline = true },
-]
-block_comment = ["<%#", "%>"]
-scope_opt_in_language_servers = ["tailwindcss-language-server"]
@@ -1,12 +0,0 @@
-(comment_directive) @comment
-
-[
- "<%#"
- "<%"
- "<%="
- "<%_"
- "<%-"
- "%>"
- "-%>"
- "_%>"
-] @keyword
@@ -1,7 +0,0 @@
-((code) @content
- (#set! "language" "ruby")
- (#set! "combined"))
-
-((content) @content
- (#set! "language" "html")
- (#set! "combined"))
@@ -1,9 +0,0 @@
-name = "GLSL"
-path_suffixes = ["vert", "frag", "tesc", "tese", "geom", "comp"]
-line_comment = "// "
-block_comment = ["/* ", " */"]
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
-]
@@ -1,118 +0,0 @@
-"break" @keyword
-"case" @keyword
-"const" @keyword
-"continue" @keyword
-"default" @keyword
-"do" @keyword
-"else" @keyword
-"enum" @keyword
-"extern" @keyword
-"for" @keyword
-"if" @keyword
-"inline" @keyword
-"return" @keyword
-"sizeof" @keyword
-"static" @keyword
-"struct" @keyword
-"switch" @keyword
-"typedef" @keyword
-"union" @keyword
-"volatile" @keyword
-"while" @keyword
-
-"#define" @keyword
-"#elif" @keyword
-"#else" @keyword
-"#endif" @keyword
-"#if" @keyword
-"#ifdef" @keyword
-"#ifndef" @keyword
-"#include" @keyword
-(preproc_directive) @keyword
-
-"--" @operator
-"-" @operator
-"-=" @operator
-"->" @operator
-"=" @operator
-"!=" @operator
-"*" @operator
-"&" @operator
-"&&" @operator
-"+" @operator
-"++" @operator
-"+=" @operator
-"<" @operator
-"==" @operator
-">" @operator
-"||" @operator
-
-"." @delimiter
-";" @delimiter
-
-(string_literal) @string
-(system_lib_string) @string
-
-(null) @constant
-(number_literal) @number
-(char_literal) @number
-
-(call_expression
- function: (identifier) @function)
-(call_expression
- function: (field_expression
- field: (field_identifier) @function))
-(function_declarator
- declarator: (identifier) @function)
-(preproc_function_def
- name: (identifier) @function.special)
-
-(field_identifier) @property
-(statement_identifier) @label
-(type_identifier) @type
-(primitive_type) @type
-(sized_type_specifier) @type
-
-((identifier) @constant
- (#match? @constant "^[A-Z][A-Z\\d_]*$"))
-
-(identifier) @variable
-
-(comment) @comment
-; inherits: c
-
-[
- "in"
- "out"
- "inout"
- "uniform"
- "shared"
- "layout"
- "attribute"
- "varying"
- "buffer"
- "coherent"
- "readonly"
- "writeonly"
- "precision"
- "highp"
- "mediump"
- "lowp"
- "centroid"
- "sample"
- "patch"
- "smooth"
- "flat"
- "noperspective"
- "invariant"
- "precise"
-] @type.qualifier
-
-"subroutine" @keyword.function
-
-(extension_storage_class) @storageclass
-
-(
- (identifier) @variable.builtin
- (#match? @variable.builtin "^gl_")
-)
@@ -1,461 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use futures::StreamExt;
-use gpui::{AsyncAppContext, Task};
-pub use language::*;
-use lazy_static::lazy_static;
-use lsp::LanguageServerBinary;
-use regex::Regex;
-use smol::{fs, process};
-use std::{
- any::Any,
- ffi::{OsStr, OsString},
- ops::Range,
- path::PathBuf,
- str,
- sync::{
- atomic::{AtomicBool, Ordering::SeqCst},
- Arc,
- },
-};
-use util::{fs::remove_matching, github::latest_github_release, ResultExt};
-
-fn server_binary_arguments() -> Vec<OsString> {
- vec!["-mode=stdio".into()]
-}
-
-#[derive(Copy, Clone)]
-pub struct GoLspAdapter;
-
-lazy_static! {
- static ref GOPLS_VERSION_REGEX: Regex = Regex::new(r"\d+\.\d+\.\d+").unwrap();
-}
-
-#[async_trait]
-impl super::LspAdapter for GoLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("gopls".into())
- }
-
- fn short_name(&self) -> &'static str {
- "gopls"
- }
-
- async fn fetch_latest_server_version(
- &self,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- let release = latest_github_release("golang/tools", false, delegate.http_client()).await?;
- let version: Option<String> = release.name.strip_prefix("gopls/v").map(str::to_string);
- if version.is_none() {
- log::warn!(
- "couldn't infer gopls version from github release name '{}'",
- release.name
- );
- }
- Ok(Box::new(version) as Box<_>)
- }
-
- fn will_fetch_server(
- &self,
- delegate: &Arc<dyn LspAdapterDelegate>,
- cx: &mut AsyncAppContext,
- ) -> Option<Task<Result<()>>> {
- static DID_SHOW_NOTIFICATION: AtomicBool = AtomicBool::new(false);
-
- const NOTIFICATION_MESSAGE: &str =
- "Could not install the Go language server `gopls`, because `go` was not found.";
-
- let delegate = delegate.clone();
- Some(cx.spawn(|cx| async move {
- let install_output = process::Command::new("go").args(["version"]).output().await;
- if install_output.is_err() {
- if DID_SHOW_NOTIFICATION
- .compare_exchange(false, true, SeqCst, SeqCst)
- .is_ok()
- {
- cx.update(|cx| {
- delegate.show_notification(NOTIFICATION_MESSAGE, cx);
- })?
- }
- return Err(anyhow!("cannot install gopls"));
- }
- Ok(())
- }))
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<Option<String>>().unwrap();
- let this = *self;
-
- if let Some(version) = *version {
- let binary_path = container_dir.join(&format!("gopls_{version}"));
- if let Ok(metadata) = fs::metadata(&binary_path).await {
- if metadata.is_file() {
- remove_matching(&container_dir, |entry| {
- entry != binary_path && entry.file_name() != Some(OsStr::new("gobin"))
- })
- .await;
-
- return Ok(LanguageServerBinary {
- path: binary_path.to_path_buf(),
- arguments: server_binary_arguments(),
- });
- }
- }
- } else if let Some(path) = this
- .cached_server_binary(container_dir.clone(), delegate)
- .await
- {
- return Ok(path);
- }
-
- let gobin_dir = container_dir.join("gobin");
- fs::create_dir_all(&gobin_dir).await?;
- let install_output = process::Command::new("go")
- .env("GO111MODULE", "on")
- .env("GOBIN", &gobin_dir)
- .args(["install", "golang.org/x/tools/gopls@latest"])
- .output()
- .await?;
- if !install_output.status.success() {
- Err(anyhow!("failed to install gopls. Is go installed?"))?;
- }
-
- let installed_binary_path = gobin_dir.join("gopls");
- let version_output = process::Command::new(&installed_binary_path)
- .arg("version")
- .output()
- .await
- .map_err(|e| anyhow!("failed to run installed gopls binary {:?}", e))?;
- let version_stdout = str::from_utf8(&version_output.stdout)
- .map_err(|_| anyhow!("gopls version produced invalid utf8"))?;
- let version = GOPLS_VERSION_REGEX
- .find(version_stdout)
- .ok_or_else(|| anyhow!("failed to parse gopls version output"))?
- .as_str();
- let binary_path = container_dir.join(&format!("gopls_{version}"));
- fs::rename(&installed_binary_path, &binary_path).await?;
-
- Ok(LanguageServerBinary {
- path: binary_path.to_path_buf(),
- arguments: server_binary_arguments(),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir)
- .await
- .map(|mut binary| {
- binary.arguments = vec!["--help".into()];
- binary
- })
- }
-
- async fn label_for_completion(
- &self,
- completion: &lsp::CompletionItem,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- let label = &completion.label;
-
- // Gopls returns nested fields and methods as completions.
- // To syntax highlight these, combine their final component
- // with their detail.
- let name_offset = label.rfind('.').unwrap_or(0);
-
- match completion.kind.zip(completion.detail.as_ref()) {
- Some((lsp::CompletionItemKind::MODULE, detail)) => {
- let text = format!("{label} {detail}");
- let source = Rope::from(format!("import {text}").as_str());
- let runs = language.highlight_text(&source, 7..7 + text.len());
- return Some(CodeLabel {
- text,
- runs,
- filter_range: 0..label.len(),
- });
- }
- Some((
- lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE,
- detail,
- )) => {
- let text = format!("{label} {detail}");
- let source =
- Rope::from(format!("var {} {}", &text[name_offset..], detail).as_str());
- let runs = adjust_runs(
- name_offset,
- language.highlight_text(&source, 4..4 + text.len()),
- );
- return Some(CodeLabel {
- text,
- runs,
- filter_range: 0..label.len(),
- });
- }
- Some((lsp::CompletionItemKind::STRUCT, _)) => {
- let text = format!("{label} struct {{}}");
- let source = Rope::from(format!("type {}", &text[name_offset..]).as_str());
- let runs = adjust_runs(
- name_offset,
- language.highlight_text(&source, 5..5 + text.len()),
- );
- return Some(CodeLabel {
- text,
- runs,
- filter_range: 0..label.len(),
- });
- }
- Some((lsp::CompletionItemKind::INTERFACE, _)) => {
- let text = format!("{label} interface {{}}");
- let source = Rope::from(format!("type {}", &text[name_offset..]).as_str());
- let runs = adjust_runs(
- name_offset,
- language.highlight_text(&source, 5..5 + text.len()),
- );
- return Some(CodeLabel {
- text,
- runs,
- filter_range: 0..label.len(),
- });
- }
- Some((lsp::CompletionItemKind::FIELD, detail)) => {
- let text = format!("{label} {detail}");
- let source =
- Rope::from(format!("type T struct {{ {} }}", &text[name_offset..]).as_str());
- let runs = adjust_runs(
- name_offset,
- language.highlight_text(&source, 16..16 + text.len()),
- );
- return Some(CodeLabel {
- text,
- runs,
- filter_range: 0..label.len(),
- });
- }
- Some((lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD, detail)) => {
- if let Some(signature) = detail.strip_prefix("func") {
- let text = format!("{label}{signature}");
- let source = Rope::from(format!("func {} {{}}", &text[name_offset..]).as_str());
- let runs = adjust_runs(
- name_offset,
- language.highlight_text(&source, 5..5 + text.len()),
- );
- return Some(CodeLabel {
- filter_range: 0..label.len(),
- text,
- runs,
- });
- }
- }
- _ => {}
- }
- None
- }
-
- async fn label_for_symbol(
- &self,
- name: &str,
- kind: lsp::SymbolKind,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- let (text, filter_range, display_range) = match kind {
- lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
- let text = format!("func {} () {{}}", name);
- let filter_range = 5..5 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::STRUCT => {
- let text = format!("type {} struct {{}}", name);
- let filter_range = 5..5 + name.len();
- let display_range = 0..text.len();
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::INTERFACE => {
- let text = format!("type {} interface {{}}", name);
- let filter_range = 5..5 + name.len();
- let display_range = 0..text.len();
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::CLASS => {
- let text = format!("type {} T", name);
- let filter_range = 5..5 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::CONSTANT => {
- let text = format!("const {} = nil", name);
- let filter_range = 6..6 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::VARIABLE => {
- let text = format!("var {} = nil", name);
- let filter_range = 4..4 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::MODULE => {
- let text = format!("package {}", name);
- let filter_range = 8..8 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- _ => return None,
- };
-
- Some(CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
- filter_range,
- })
- }
-}
-
-async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last_binary_path = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_file()
- && entry
- .file_name()
- .to_str()
- .map_or(false, |name| name.starts_with("gopls_"))
- {
- last_binary_path = Some(entry.path());
- }
- }
-
- if let Some(path) = last_binary_path {
- Ok(LanguageServerBinary {
- path,
- arguments: server_binary_arguments(),
- })
- } else {
- Err(anyhow!("no cached binary"))
- }
- })()
- .await
- .log_err()
-}
-
-fn adjust_runs(
- delta: usize,
- mut runs: Vec<(Range<usize>, HighlightId)>,
-) -> Vec<(Range<usize>, HighlightId)> {
- for (range, _) in &mut runs {
- range.start += delta;
- range.end += delta;
- }
- runs
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::languages::language;
- use gpui::Hsla;
- use theme::SyntaxTheme;
-
- #[gpui::test]
- async fn test_go_label_for_completion() {
- let language = language(
- "go",
- tree_sitter_go::language(),
- Some(Arc::new(GoLspAdapter)),
- )
- .await;
-
- let theme = SyntaxTheme::new_test([
- ("type", Hsla::default()),
- ("keyword", Hsla::default()),
- ("function", Hsla::default()),
- ("number", Hsla::default()),
- ("property", Hsla::default()),
- ]);
- language.set_theme(&theme);
-
- let grammar = language.grammar().unwrap();
- let highlight_function = grammar.highlight_id_for_name("function").unwrap();
- let highlight_type = grammar.highlight_id_for_name("type").unwrap();
- let highlight_keyword = grammar.highlight_id_for_name("keyword").unwrap();
- let highlight_number = grammar.highlight_id_for_name("number").unwrap();
- let highlight_field = grammar.highlight_id_for_name("property").unwrap();
-
- assert_eq!(
- language
- .label_for_completion(&lsp::CompletionItem {
- kind: Some(lsp::CompletionItemKind::FUNCTION),
- label: "Hello".to_string(),
- detail: Some("func(a B) c.D".to_string()),
- ..Default::default()
- })
- .await,
- Some(CodeLabel {
- text: "Hello(a B) c.D".to_string(),
- filter_range: 0..5,
- runs: vec![
- (0..5, highlight_function),
- (8..9, highlight_type),
- (13..14, highlight_type),
- ],
- })
- );
-
- // Nested methods
- assert_eq!(
- language
- .label_for_completion(&lsp::CompletionItem {
- kind: Some(lsp::CompletionItemKind::METHOD),
- label: "one.two.Three".to_string(),
- detail: Some("func() [3]interface{}".to_string()),
- ..Default::default()
- })
- .await,
- Some(CodeLabel {
- text: "one.two.Three() [3]interface{}".to_string(),
- filter_range: 0..13,
- runs: vec![
- (8..13, highlight_function),
- (17..18, highlight_number),
- (19..28, highlight_keyword),
- ],
- })
- );
-
- // Nested fields
- assert_eq!(
- language
- .label_for_completion(&lsp::CompletionItem {
- kind: Some(lsp::CompletionItemKind::FIELD),
- label: "two.Three".to_string(),
- detail: Some("a.Bcd".to_string()),
- ..Default::default()
- })
- .await,
- Some(CodeLabel {
- text: "two.Three a.Bcd".to_string(),
- filter_range: 0..9,
- runs: vec![(4..9, highlight_field), (12..15, highlight_type)],
- })
- );
- }
-}
@@ -1,3 +0,0 @@
-("[" @open "]" @close)
-("{" @open "}" @close)
-("\"" @open "\"" @close)
@@ -1,12 +0,0 @@
-name = "Go"
-path_suffixes = ["go"]
-line_comment = "// "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
- { start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
-]
@@ -1,24 +0,0 @@
-(
- (comment)* @context
- .
- (type_declaration
- (type_spec
- name: (_) @name)
- ) @item
-)
-
-(
- (comment)* @context
- .
- (function_declaration
- name: (_) @name
- ) @item
-)
-
-(
- (comment)* @context
- .
- (method_declaration
- name: (_) @name
- ) @item
-)
@@ -1,107 +0,0 @@
-(identifier) @variable
-(type_identifier) @type
-(field_identifier) @property
-
-(call_expression
- function: (identifier) @function)
-
-(call_expression
- function: (selector_expression
- field: (field_identifier) @function.method))
-
-(function_declaration
- name: (identifier) @function)
-
-(method_declaration
- name: (field_identifier) @function.method)
-
-[
- "--"
- "-"
- "-="
- ":="
- "!"
- "!="
- "..."
- "*"
- "*"
- "*="
- "/"
- "/="
- "&"
- "&&"
- "&="
- "%"
- "%="
- "^"
- "^="
- "+"
- "++"
- "+="
- "<-"
- "<"
- "<<"
- "<<="
- "<="
- "="
- "=="
- ">"
- ">="
- ">>"
- ">>="
- "|"
- "|="
- "||"
- "~"
-] @operator
-
-[
- "break"
- "case"
- "chan"
- "const"
- "continue"
- "default"
- "defer"
- "else"
- "fallthrough"
- "for"
- "func"
- "go"
- "goto"
- "if"
- "import"
- "interface"
- "map"
- "package"
- "range"
- "return"
- "select"
- "struct"
- "switch"
- "type"
- "var"
-] @keyword
-
-[
- (interpreted_string_literal)
- (raw_string_literal)
- (rune_literal)
-] @string
-
-(escape_sequence) @escape
-
-[
- (int_literal)
- (float_literal)
- (imaginary_literal)
-] @number
-
-[
- (true)
- (false)
- (nil)
- (iota)
-] @constant.builtin
-
-(comment) @comment
@@ -1,9 +0,0 @@
-[
- (assignment_statement)
- (call_expression)
- (selector_expression)
-] @indent
-
-(_ "[" "]" @end) @indent
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,43 +0,0 @@
-(type_declaration
- "type" @context
- (type_spec
- name: (_) @name)) @item
-
-(function_declaration
- "func" @context
- name: (identifier) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)) @item
-
-(method_declaration
- "func" @context
- receiver: (parameter_list
- "(" @context
- (parameter_declaration
- type: (_) @context)
- ")" @context)
- name: (field_identifier) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)) @item
-
-(const_declaration
- "const" @context
- (const_spec
- name: (identifier) @name) @item)
-
-(source_file
- (var_declaration
- "var" @context
- (var_spec
- name: (identifier) @name) @item))
-
-(method_spec
- name: (_) @name
- parameters: (parameter_list
- "(" @context
- ")" @context)) @item
-
-(field_declaration
- name: (_) @name) @item
@@ -1,6 +0,0 @@
-(comment) @comment
-[
- (interpreted_string_literal)
- (raw_string_literal)
- (rune_literal)
-] @string
@@ -1,12 +0,0 @@
-name = "HEEX"
-path_suffixes = ["heex"]
-autoclose_before = ">})"
-brackets = [
- { start = "<", end = ">", close = true, newline = true },
-]
-block_comment = ["<%!-- ", " --%>"]
-scope_opt_in_language_servers = ["tailwindcss-language-server"]
-
-[overrides.string]
-word_characters = ["-"]
-opt_into_language_servers = ["tailwindcss-language-server"]
@@ -1,57 +0,0 @@
-; HEEx delimiters
-[
- "/>"
- "<!"
- "<"
- "</"
- "</:"
- "<:"
- ">"
- "{"
- "}"
-] @punctuation.bracket
-
-[
- "<%!--"
- "<%"
- "<%#"
- "<%%="
- "<%="
- "%>"
- "--%>"
- "-->"
- "<!--"
-] @keyword
-
-; HEEx operators are highlighted as such
-"=" @operator
-
-; HEEx inherits the DOCTYPE tag from HTML
-(doctype) @constant
-
-(comment) @comment
-
-; HEEx tags and slots are highlighted as HTML
-[
- (tag_name)
- (slot_name)
-] @tag
-
-; HEEx attributes are highlighted as HTML attributes
-(attribute_name) @attribute
-
-; HEEx special attributes are highlighted as keywords
-(special_attribute_name) @keyword
-
-[
- (attribute_value)
- (quoted_attribute_value)
-] @string
-
-; HEEx components are highlighted as Elixir modules and functions
-(component_name
- [
- (module) @module
- (function) @function
- "." @punctuation.delimiter
- ])
@@ -1,13 +0,0 @@
-(
- (directive
- [
- (partial_expression_value)
- (expression_value)
- (ending_expression_value)
- ] @content)
- (#set! language "elixir")
- (#set! combined)
-)
-
-((expression (expression_value) @content)
- (#set! language "elixir"))
@@ -1,4 +0,0 @@
-[
- (attribute_value)
- (quoted_attribute_value)
-] @string
@@ -1,130 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use futures::StreamExt;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use node_runtime::NodeRuntime;
-use serde_json::json;
-use smol::fs;
-use std::{
- any::Any,
- ffi::OsString,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::ResultExt;
-
-const SERVER_PATH: &'static str =
- "node_modules/vscode-langservers-extracted/bin/vscode-html-language-server";
-
-fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-pub struct HtmlLspAdapter {
- node: Arc<dyn NodeRuntime>,
-}
-
-impl HtmlLspAdapter {
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- HtmlLspAdapter { node }
- }
-}
-
-#[async_trait]
-impl LspAdapter for HtmlLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("vscode-html-language-server".into())
- }
-
- fn short_name(&self) -> &'static str {
- "html"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Any + Send>> {
- Ok(Box::new(
- self.node
- .npm_package_latest_version("vscode-langservers-extracted")
- .await?,
- ) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<String>().unwrap();
- let server_path = container_dir.join(SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(
- &container_dir,
- &[("vscode-langservers-extracted", version.as_str())],
- )
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn initialization_options(&self) -> Option<serde_json::Value> {
- Some(json!({
- "provideFormatter": true
- }))
- }
-}
-
-async fn get_cached_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last_version_dir = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_dir() {
- last_version_dir = Some(entry.path());
- }
- }
- let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
- let server_path = last_version_dir.join(SERVER_PATH);
- if server_path.exists() {
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- } else {
- Err(anyhow!(
- "missing executable in directory {:?}",
- last_version_dir
- ))
- }
- })()
- .await
- .log_err()
-}
@@ -1,2 +0,0 @@
-("<" @open ">" @close)
-("\"" @open "\"" @close)
@@ -1,14 +0,0 @@
-name = "HTML"
-path_suffixes = ["html"]
-autoclose_before = ">})"
-block_comment = ["<!-- ", " -->"]
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
- { start = "<", end = ">", close = true, newline = true, not_in = ["comment", "string"] },
- { start = "!--", end = " --", close = true, newline = false, not_in = ["comment", "string"] },
-]
-word_characters = ["-"]
-prettier_parser_name = "html"
@@ -1,15 +0,0 @@
-(tag_name) @keyword
-(erroneous_end_tag_name) @keyword
-(doctype) @constant
-(attribute_name) @property
-(attribute_value) @string
-(comment) @comment
-
-"=" @operator
-
-[
- "<"
- ">"
- "</"
- "/>"
-] @punctuation.bracket
@@ -1,6 +0,0 @@
-(start_tag ">" @end) @indent
-(self_closing_tag "/>" @end) @indent
-
-(element
- (start_tag) @start
- (end_tag)? @end) @indent
@@ -1,7 +0,0 @@
-(script_element
- (raw_text) @content
- (#set! "language" "javascript"))
-
-(style_element
- (raw_text) @content
- (#set! "language" "css"))
@@ -1,2 +0,0 @@
-(comment) @comment
-(quoted_attribute_value) @string
@@ -1,5 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
-("<" @open ">" @close)
-("\"" @open "\"" @close)
@@ -1,26 +0,0 @@
-name = "JavaScript"
-path_suffixes = ["js", "jsx", "mjs", "cjs"]
-first_line_pattern = '^#!.*\bnode\b'
-line_comment = "// "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "<", end = ">", close = false, newline = true, not_in = ["comment", "string"] },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
- { start = "`", end = "`", close = true, newline = false, not_in = ["comment", "string"] },
- { start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
-]
-word_characters = ["$", "#"]
-scope_opt_in_language_servers = ["tailwindcss-language-server"]
-prettier_parser_name = "babel"
-
-[overrides.element]
-line_comment = { remove = true }
-block_comment = ["{/* ", " */}"]
-
-[overrides.string]
-word_characters = ["-"]
-opt_into_language_servers = ["tailwindcss-language-server"]
@@ -1,71 +0,0 @@
-(
- (comment)* @context
- .
- [
- (export_statement
- (function_declaration
- "async"? @name
- "function" @name
- name: (_) @name))
- (function_declaration
- "async"? @name
- "function" @name
- name: (_) @name)
- ] @item
-)
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (class_declaration
- "class" @name
- name: (_) @name))
- (class_declaration
- "class" @name
- name: (_) @name)
- ] @item
-)
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (interface_declaration
- "interface" @name
- name: (_) @name))
- (interface_declaration
- "interface" @name
- name: (_) @name)
- ] @item
-)
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (enum_declaration
- "enum" @name
- name: (_) @name))
- (enum_declaration
- "enum" @name
- name: (_) @name)
- ] @item
-)
-
-(
- (comment)* @context
- .
- (method_definition
- [
- "get"
- "set"
- "async"
- "*"
- "static"
- ]* @name
- name: (_) @name) @item
-)
@@ -1,217 +0,0 @@
-; Variables
-
-(identifier) @variable
-
-; Properties
-
-(property_identifier) @property
-
-; Function and method calls
-
-(call_expression
- function: (identifier) @function)
-
-(call_expression
- function: (member_expression
- property: (property_identifier) @function.method))
-
-; Function and method definitions
-
-(function
- name: (identifier) @function)
-(function_declaration
- name: (identifier) @function)
-(method_definition
- name: (property_identifier) @function.method)
-
-(pair
- key: (property_identifier) @function.method
- value: [(function) (arrow_function)])
-
-(assignment_expression
- left: (member_expression
- property: (property_identifier) @function.method)
- right: [(function) (arrow_function)])
-
-(variable_declarator
- name: (identifier) @function
- value: [(function) (arrow_function)])
-
-(assignment_expression
- left: (identifier) @function
- right: [(function) (arrow_function)])
-
-; Special identifiers
-
-((identifier) @type
- (#match? @type "^[A-Z]"))
-(type_identifier) @type
-(predefined_type) @type.builtin
-
-([
- (identifier)
- (shorthand_property_identifier)
- (shorthand_property_identifier_pattern)
- ] @constant
- (#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
-
-; Literals
-
-(this) @variable.special
-(super) @variable.special
-
-[
- (null)
- (undefined)
-] @constant.builtin
-
-[
- (true)
- (false)
-] @boolean
-
-(comment) @comment
-
-[
- (string)
- (template_string)
-] @string
-
-(regex) @string.regex
-(number) @number
-
-; Tokens
-
-[
- ";"
- "?."
- "."
- ","
- ":"
-] @punctuation.delimiter
-
-[
- "-"
- "--"
- "-="
- "+"
- "++"
- "+="
- "*"
- "*="
- "**"
- "**="
- "/"
- "/="
- "%"
- "%="
- "<"
- "<="
- "<<"
- "<<="
- "="
- "=="
- "==="
- "!"
- "!="
- "!=="
- "=>"
- ">"
- ">="
- ">>"
- ">>="
- ">>>"
- ">>>="
- "~"
- "^"
- "&"
- "|"
- "^="
- "&="
- "|="
- "&&"
- "||"
- "??"
- "&&="
- "||="
- "??="
-] @operator
-
-[
- "("
- ")"
- "["
- "]"
- "{"
- "}"
-] @punctuation.bracket
-
-[
- "as"
- "async"
- "await"
- "break"
- "case"
- "catch"
- "class"
- "const"
- "continue"
- "debugger"
- "default"
- "delete"
- "do"
- "else"
- "export"
- "extends"
- "finally"
- "for"
- "from"
- "function"
- "get"
- "if"
- "import"
- "in"
- "instanceof"
- "let"
- "new"
- "of"
- "return"
- "set"
- "static"
- "switch"
- "target"
- "throw"
- "try"
- "typeof"
- "var"
- "void"
- "while"
- "with"
- "yield"
-] @keyword
-
-(template_substitution
- "${" @punctuation.special
- "}" @punctuation.special) @embedded
-
-(type_arguments
- "<" @punctuation.bracket
- ">" @punctuation.bracket)
-
-; Keywords
-
-[ "abstract"
- "declare"
- "enum"
- "export"
- "implements"
- "interface"
- "keyof"
- "namespace"
- "private"
- "protected"
- "public"
- "type"
- "readonly"
- "override"
-] @keyword
@@ -1,15 +0,0 @@
-[
- (call_expression)
- (assignment_expression)
- (member_expression)
- (lexical_declaration)
- (variable_declaration)
- (assignment_expression)
- (if_statement)
- (for_statement)
-] @indent
-
-(_ "[" "]" @end) @indent
-(_ "<" ">" @end) @indent
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,62 +0,0 @@
-(internal_module
- "namespace" @context
- name: (_) @name) @item
-
-(enum_declaration
- "enum" @context
- name: (_) @name) @item
-
-(function_declaration
- "async"? @context
- "function" @context
- name: (_) @name
- parameters: (formal_parameters
- "(" @context
- ")" @context)) @item
-
-(interface_declaration
- "interface" @context
- name: (_) @name) @item
-
-(program
- (export_statement
- (lexical_declaration
- ["let" "const"] @context
- (variable_declarator
- name: (_) @name) @item)))
-
-(program
- (lexical_declaration
- ["let" "const"] @context
- (variable_declarator
- name: (_) @name) @item))
-
-(class_declaration
- "class" @context
- name: (_) @name) @item
-
-(method_definition
- [
- "get"
- "set"
- "async"
- "*"
- "readonly"
- "static"
- (override_modifier)
- (accessibility_modifier)
- ]* @context
- name: (_) @name
- parameters: (formal_parameters
- "(" @context
- ")" @context)) @item
-
-(public_field_definition
- [
- "declare"
- "readonly"
- "abstract"
- "static"
- (accessibility_modifier)
- ]* @context
- name: (_) @name) @item
@@ -1,18 +0,0 @@
-(comment) @comment
-
-[
- (string)
- (template_string)
-] @string
-
-[
- (jsx_element)
- (jsx_fragment)
-] @element
-
-[
- (jsx_opening_element)
- (jsx_closing_element)
- (jsx_self_closing_element)
- (jsx_expression)
-] @default
@@ -1,185 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use collections::HashMap;
-use feature_flags::FeatureFlagAppExt;
-use futures::{future::BoxFuture, FutureExt, StreamExt};
-use gpui::AppContext;
-use language::{LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use node_runtime::NodeRuntime;
-use serde_json::json;
-use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
-use smol::fs;
-use std::{
- any::Any,
- ffi::OsString,
- future,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::{paths, ResultExt};
-
-const SERVER_PATH: &'static str =
- "node_modules/vscode-json-languageserver/bin/vscode-json-languageserver";
-
-fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-pub struct JsonLspAdapter {
- node: Arc<dyn NodeRuntime>,
- languages: Arc<LanguageRegistry>,
-}
-
-impl JsonLspAdapter {
- pub fn new(node: Arc<dyn NodeRuntime>, languages: Arc<LanguageRegistry>) -> Self {
- JsonLspAdapter { node, languages }
- }
-}
-
-#[async_trait]
-impl LspAdapter for JsonLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("json-language-server".into())
- }
-
- fn short_name(&self) -> &'static str {
- "json"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- Ok(Box::new(
- self.node
- .npm_package_latest_version("vscode-json-languageserver")
- .await?,
- ) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<String>().unwrap();
- let server_path = container_dir.join(SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(
- &container_dir,
- &[("vscode-json-languageserver", version.as_str())],
- )
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn initialization_options(&self) -> Option<serde_json::Value> {
- Some(json!({
- "provideFormatter": true
- }))
- }
-
- fn workspace_configuration(
- &self,
- _workspace_root: &Path,
- cx: &mut AppContext,
- ) -> BoxFuture<'static, serde_json::Value> {
- let action_names = cx.all_action_names();
- let staff_mode = cx.is_staff();
- let language_names = &self.languages.language_names();
- let settings_schema = cx.global::<SettingsStore>().json_schema(
- &SettingsJsonSchemaParams {
- language_names,
- staff_mode,
- },
- cx,
- );
-
- future::ready(serde_json::json!({
- "json": {
- "format": {
- "enable": true,
- },
- "schemas": [
- {
- "fileMatch": [
- schema_file_match(&paths::SETTINGS),
- &*paths::LOCAL_SETTINGS_RELATIVE_PATH,
- ],
- "schema": settings_schema,
- },
- {
- "fileMatch": [schema_file_match(&paths::KEYMAP)],
- "schema": KeymapFile::generate_json_schema(&action_names),
- }
- ]
- }
- }))
- .boxed()
- }
-
- async fn language_ids(&self) -> HashMap<String, String> {
- [("JSON".into(), "jsonc".into())].into_iter().collect()
- }
-}
-
-async fn get_cached_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last_version_dir = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_dir() {
- last_version_dir = Some(entry.path());
- }
- }
-
- let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
- let server_path = last_version_dir.join(SERVER_PATH);
- if server_path.exists() {
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- } else {
- Err(anyhow!(
- "missing executable in directory {:?}",
- last_version_dir
- ))
- }
- })()
- .await
- .log_err()
-}
-
-fn schema_file_match(path: &Path) -> &Path {
- path.strip_prefix(path.parent().unwrap().parent().unwrap())
- .unwrap()
-}
@@ -1,3 +0,0 @@
-("[" @open "]" @close)
-("{" @open "}" @close)
-("\"" @open "\"" @close)
@@ -1,10 +0,0 @@
-name = "JSON"
-path_suffixes = ["json"]
-line_comment = "// "
-autoclose_before = ",]}"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
-]
-prettier_parser_name = "json"
@@ -1,14 +0,0 @@
-; Only produce one embedding for the entire file.
-(document) @item
-
-; Collapse arrays, except for the first object.
-(array
- "[" @keep
- .
- (object)? @keep
- "]" @keep) @collapse
-
-; Collapse string values (but not keys).
-(pair value: (string
- "\"" @keep
- "\"" @keep) @collapse)
@@ -1,21 +0,0 @@
-(comment) @comment
-
-(string) @string
-
-(pair
- key: (string) @property)
-
-(number) @number
-
-[
- (true)
- (false)
- (null)
-] @constant
-
-[
- "{"
- "}"
- "["
- "]"
-] @punctuation.bracket
@@ -1,2 +0,0 @@
-(array "]" @end) @indent
-(object "}" @end) @indent
@@ -1,2 +0,0 @@
-(pair
- key: (string (string_content) @name)) @item
@@ -1 +0,0 @@
-(string) @string
@@ -1,168 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use collections::HashMap;
-use futures::lock::Mutex;
-use gpui::executor::Background;
-use language2::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp2::LanguageServerBinary;
-use plugin_runtime::{Plugin, PluginBinary, PluginBuilder, WasiFn};
-use std::{any::Any, path::PathBuf, sync::Arc};
-use util::ResultExt;
-
-#[allow(dead_code)]
-pub async fn new_json(executor: Arc<Background>) -> Result<PluginLspAdapter> {
- let plugin = PluginBuilder::new_default()?
- .host_function_async("command", |command: String| async move {
- let mut args = command.split(' ');
- let command = args.next().unwrap();
- smol::process::Command::new(command)
- .args(args)
- .output()
- .await
- .log_err()
- .map(|output| output.stdout)
- })?
- .init(PluginBinary::Precompiled(include_bytes!(
- "../../../../plugins/bin/json_language.wasm.pre",
- )))
- .await?;
-
- PluginLspAdapter::new(plugin, executor).await
-}
-
-pub struct PluginLspAdapter {
- name: WasiFn<(), String>,
- fetch_latest_server_version: WasiFn<(), Option<String>>,
- fetch_server_binary: WasiFn<(PathBuf, String), Result<LanguageServerBinary, String>>,
- cached_server_binary: WasiFn<PathBuf, Option<LanguageServerBinary>>,
- initialization_options: WasiFn<(), String>,
- language_ids: WasiFn<(), Vec<(String, String)>>,
- executor: Arc<Background>,
- runtime: Arc<Mutex<Plugin>>,
-}
-
-impl PluginLspAdapter {
- #[allow(unused)]
- pub async fn new(mut plugin: Plugin, executor: Arc<Background>) -> Result<Self> {
- Ok(Self {
- name: plugin.function("name")?,
- fetch_latest_server_version: plugin.function("fetch_latest_server_version")?,
- fetch_server_binary: plugin.function("fetch_server_binary")?,
- cached_server_binary: plugin.function("cached_server_binary")?,
- initialization_options: plugin.function("initialization_options")?,
- language_ids: plugin.function("language_ids")?,
- executor,
- runtime: Arc::new(Mutex::new(plugin)),
- })
- }
-}
-
-#[async_trait]
-impl LspAdapter for PluginLspAdapter {
- async fn name(&self) -> LanguageServerName {
- let name: String = self
- .runtime
- .lock()
- .await
- .call(&self.name, ())
- .await
- .unwrap();
- LanguageServerName(name.into())
- }
-
- fn short_name(&self) -> &'static str {
- "PluginLspAdapter"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- let runtime = self.runtime.clone();
- let function = self.fetch_latest_server_version;
- self.executor
- .spawn(async move {
- let mut runtime = runtime.lock().await;
- let versions: Result<Option<String>> =
- runtime.call::<_, Option<String>>(&function, ()).await;
- versions
- .map_err(|e| anyhow!("{}", e))?
- .ok_or_else(|| anyhow!("Could not fetch latest server version"))
- .map(|v| Box::new(v) as Box<_>)
- })
- .await
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = *version.downcast::<String>().unwrap();
- let runtime = self.runtime.clone();
- let function = self.fetch_server_binary;
- self.executor
- .spawn(async move {
- let mut runtime = runtime.lock().await;
- let handle = runtime.attach_path(&container_dir)?;
- let result: Result<LanguageServerBinary, String> =
- runtime.call(&function, (container_dir, version)).await?;
- runtime.remove_resource(handle)?;
- result.map_err(|e| anyhow!("{}", e))
- })
- .await
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- let runtime = self.runtime.clone();
- let function = self.cached_server_binary;
-
- self.executor
- .spawn(async move {
- let mut runtime = runtime.lock().await;
- let handle = runtime.attach_path(&container_dir).ok()?;
- let result: Option<LanguageServerBinary> =
- runtime.call(&function, container_dir).await.ok()?;
- runtime.remove_resource(handle).ok()?;
- result
- })
- .await
- }
-
- fn can_be_reinstalled(&self) -> bool {
- false
- }
-
- async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
- None
- }
-
- async fn initialization_options(&self) -> Option<serde_json::Value> {
- let string: String = self
- .runtime
- .lock()
- .await
- .call(&self.initialization_options, ())
- .await
- .log_err()?;
-
- serde_json::from_str(&string).ok()
- }
-
- async fn language_ids(&self) -> HashMap<String, String> {
- self.runtime
- .lock()
- .await
- .call(&self.language_ids, ())
- .await
- .log_err()
- .unwrap_or_default()
- .into_iter()
- .collect()
- }
-}
@@ -1,135 +0,0 @@
-use anyhow::{anyhow, bail, Result};
-use async_compression::futures::bufread::GzipDecoder;
-use async_tar::Archive;
-use async_trait::async_trait;
-use futures::{io::BufReader, StreamExt};
-use language::{LanguageServerName, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use smol::fs;
-use std::{any::Any, env::consts, path::PathBuf};
-use util::{
- async_maybe,
- github::{latest_github_release, GitHubLspBinaryVersion},
- ResultExt,
-};
-
-#[derive(Copy, Clone)]
-pub struct LuaLspAdapter;
-
-#[async_trait]
-impl super::LspAdapter for LuaLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("lua-language-server".into())
- }
-
- fn short_name(&self) -> &'static str {
- "lua"
- }
-
- async fn fetch_latest_server_version(
- &self,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- let release =
- latest_github_release("LuaLS/lua-language-server", false, delegate.http_client())
- .await?;
- let version = release.name.clone();
- let platform = match consts::ARCH {
- "x86_64" => "x64",
- "aarch64" => "arm64",
- other => bail!("Running on unsupported platform: {other}"),
- };
- let asset_name = format!("lua-language-server-{version}-darwin-{platform}.tar.gz");
- let asset = release
- .assets
- .iter()
- .find(|asset| asset.name == asset_name)
- .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?;
- let version = GitHubLspBinaryVersion {
- name: release.name.clone(),
- url: asset.browser_download_url.clone(),
- };
- Ok(Box::new(version) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
-
- let binary_path = container_dir.join("bin/lua-language-server");
-
- if fs::metadata(&binary_path).await.is_err() {
- let mut response = delegate
- .http_client()
- .get(&version.url, Default::default(), true)
- .await
- .map_err(|err| anyhow!("error downloading release: {}", err))?;
- let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
- let archive = Archive::new(decompressed_bytes);
- archive.unpack(container_dir).await?;
- }
-
- fs::set_permissions(
- &binary_path,
- <fs::Permissions as fs::unix::PermissionsExt>::from_mode(0o755),
- )
- .await?;
- Ok(LanguageServerBinary {
- path: binary_path,
- arguments: Vec::new(),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir)
- .await
- .map(|mut binary| {
- binary.arguments = vec!["--version".into()];
- binary
- })
- }
-}
-
-async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServerBinary> {
- async_maybe!({
- let mut last_binary_path = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_file()
- && entry
- .file_name()
- .to_str()
- .map_or(false, |name| name == "lua-language-server")
- {
- last_binary_path = Some(entry.path());
- }
- }
-
- if let Some(path) = last_binary_path {
- Ok(LanguageServerBinary {
- path,
- arguments: Vec::new(),
- })
- } else {
- Err(anyhow!("no cached binary"))
- }
- })
- .await
- .log_err()
-}
@@ -1,3 +0,0 @@
-("[" @open "]" @close)
-("{" @open "}" @close)
-("(" @open ")" @close)
@@ -1,10 +0,0 @@
-name = "Lua"
-path_suffixes = ["lua"]
-line_comment = "-- "
-autoclose_before = ",]}"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
-]
-collapsed_placeholder = "--[ ... ]--"
@@ -1,10 +0,0 @@
-(
- (comment)* @context
- .
- (function_declaration
- "function" @name
- name: (_) @name
- (comment)* @collapse
- body: (block) @collapse
- ) @item
-)
@@ -1,198 +0,0 @@
-;; Keywords
-
-"return" @keyword
-
-[
- "goto"
- "in"
- "local"
-] @keyword
-
-(break_statement) @keyword
-
-(do_statement
-[
- "do"
- "end"
-] @keyword)
-
-(while_statement
-[
- "while"
- "do"
- "end"
-] @keyword)
-
-(repeat_statement
-[
- "repeat"
- "until"
-] @keyword)
-
-(if_statement
-[
- "if"
- "elseif"
- "else"
- "then"
- "end"
-] @keyword)
-
-(elseif_statement
-[
- "elseif"
- "then"
- "end"
-] @keyword)
-
-(else_statement
-[
- "else"
- "end"
-] @keyword)
-
-(for_statement
-[
- "for"
- "do"
- "end"
-] @keyword)
-
-(function_declaration
-[
- "function"
- "end"
-] @keyword)
-
-(function_definition
-[
- "function"
- "end"
-] @keyword)
-
-;; Operators
-
-[
- "and"
- "not"
- "or"
-] @operator
-
-[
- "+"
- "-"
- "*"
- "/"
- "%"
- "^"
- "#"
- "=="
- "~="
- "<="
- ">="
- "<"
- ">"
- "="
- "&"
- "~"
- "|"
- "<<"
- ">>"
- "//"
- ".."
-] @operator
-
-;; Punctuations
-
-[
- ";"
- ":"
- ","
- "."
-] @punctuation.delimiter
-
-;; Brackets
-
-[
- "("
- ")"
- "["
- "]"
- "{"
- "}"
-] @punctuation.bracket
-
-;; Variables
-
-(identifier) @variable
-
-((identifier) @variable.special
- (#eq? @variable.special "self"))
-
-(variable_list
- attribute: (attribute
- (["<" ">"] @punctuation.bracket
- (identifier) @attribute)))
-
-;; Constants
-
-((identifier) @constant
- (#match? @constant "^[A-Z][A-Z_0-9]*$"))
-
-(vararg_expression) @constant
-
-(nil) @constant.builtin
-
-[
- (false)
- (true)
-] @boolean
-
-;; Tables
-
-(field name: (identifier) @field)
-
-(dot_index_expression field: (identifier) @field)
-
-(table_constructor
-[
- "{"
- "}"
-] @constructor)
-
-;; Functions
-
-(parameters (identifier) @parameter)
-
-(function_call
- name: [
- (identifier) @function
- (dot_index_expression field: (identifier) @function)
- ])
-
-(function_declaration
- name: [
- (identifier) @function.definition
- (dot_index_expression field: (identifier) @function.definition)
- ])
-
-(method_index_expression method: (identifier) @method)
-
-(function_call
- (identifier) @function.builtin
- (#any-of? @function.builtin
- ;; built-in functions in Lua 5.1
- "assert" "collectgarbage" "dofile" "error" "getfenv" "getmetatable" "ipairs"
- "load" "loadfile" "loadstring" "module" "next" "pairs" "pcall" "print"
- "rawequal" "rawget" "rawset" "require" "select" "setfenv" "setmetatable"
- "tonumber" "tostring" "type" "unpack" "xpcall"))
-
-;; Others
-
-(comment) @comment
-
-(hash_bang_line) @preproc
-
-(number) @number
-
-(string) @string
@@ -1,10 +0,0 @@
-(if_statement "end" @end) @indent
-(do_statement "end" @end) @indent
-(while_statement "end" @end) @indent
-(for_statement "end" @end) @indent
-(repeat_statement "until" @end) @indent
-(function_declaration "end" @end) @indent
-
-(_ "[" "]" @end) @indent
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,3 +0,0 @@
-(function_declaration
- "function" @context
- name: (_) @name) @item
@@ -1,11 +0,0 @@
-name = "Markdown"
-path_suffixes = ["md", "mdx"]
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "<", end = ">", close = true, newline = true },
- { start = "\"", end = "\"", close = false, newline = false },
- { start = "'", end = "'", close = false, newline = false },
- { start = "`", end = "`", close = false, newline = false },
-]
@@ -1,24 +0,0 @@
-(emphasis) @emphasis
-(strong_emphasis) @emphasis.strong
-
-[
- (atx_heading)
- (setext_heading)
-] @title
-
-[
- (list_marker_plus)
- (list_marker_minus)
- (list_marker_star)
- (list_marker_dot)
- (list_marker_parenthesis)
-] @punctuation.list_marker
-
-(code_span) @text.literal
-
-(fenced_code_block
- (info_string
- (language) @text.literal))
-
-(link_destination) @link_uri
-(link_text) @link_text
@@ -1,4 +0,0 @@
-(fenced_code_block
- (info_string
- (language) @language)
- (code_fence_content) @content)
@@ -1,11 +0,0 @@
-name = "Nix"
-path_suffixes = ["nix"]
-line_comment = "# "
-block_comment = ["/* ", " */"]
-autoclose_before = ";:.,=}])>` \n\t\""
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "<", end = ">", close = true, newline = true },
-]
@@ -1,95 +0,0 @@
-(comment) @comment
-
-[
- "if"
- "then"
- "else"
- "let"
- "inherit"
- "in"
- "rec"
- "with"
- "assert"
- "or"
-] @keyword
-
-[
- (string_expression)
- (indented_string_expression)
-] @string
-
-[
- (path_expression)
- (hpath_expression)
- (spath_expression)
-] @string.special.path
-
-(uri_expression) @link_uri
-
-[
- (integer_expression)
- (float_expression)
-] @number
-
-(interpolation
- "${" @punctuation.special
- "}" @punctuation.special) @embedded
-
-(escape_sequence) @escape
-(dollar_escape) @escape
-
-(function_expression
- universal: (identifier) @parameter
-)
-
-(formal
- name: (identifier) @parameter
- "?"? @punctuation.delimiter)
-
-(select_expression
- attrpath: (attrpath (identifier)) @property)
-
-(apply_expression
- function: [
- (variable_expression (identifier)) @function
- (select_expression
- attrpath: (attrpath
- attr: (identifier) @function .))])
-
-(unary_expression
- operator: _ @operator)
-
-(binary_expression
- operator: _ @operator)
-
-(variable_expression (identifier) @variable)
-
-(binding
- attrpath: (attrpath (identifier)) @property)
-
-"=" @operator
-
-[
- ";"
- "."
- ","
-] @punctuation.delimiter
-
-[
- "("
- ")"
- "["
- "]"
- "{"
- "}"
-] @punctuation.bracket
-
-(identifier) @variable
-
-((identifier) @function.builtin
@@ -1,55 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use std::{any::Any, path::PathBuf};
-
-pub struct NuLanguageServer;
-
-#[async_trait]
-impl LspAdapter for NuLanguageServer {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("nu".into())
- }
-
- fn short_name(&self) -> &'static str {
- "nu"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Any + Send>> {
- Ok(Box::new(()))
- }
-
- async fn fetch_server_binary(
- &self,
- _version: Box<dyn 'static + Send + Any>,
- _container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- Err(anyhow!(
- "nu v0.87.0 or greater must be installed and available in your $PATH"
- ))
- }
-
- async fn cached_server_binary(
- &self,
- _: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- Some(LanguageServerBinary {
- path: "nu".into(),
- arguments: vec!["--lsp".into()],
- })
- }
-
- fn can_be_reinstalled(&self) -> bool {
- false
- }
-
- async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
- None
- }
-}
@@ -1,4 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
-(parameter_pipes "|" @open "|" @close)
@@ -1,9 +0,0 @@
-name = "Nu"
-path_suffixes = ["nu"]
-line_comment = "# "
-autoclose_before = ";:.,=}])>` \n\t\""
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
-]
@@ -1,302 +0,0 @@
-;;; ---
-;;; keywords
-[
- "def"
- "def-env"
- "alias"
- "export-env"
- "export"
- "extern"
- "module"
-
- "let"
- "let-env"
- "mut"
- "const"
-
- "hide-env"
-
- "source"
- "source-env"
-
- "overlay"
- "register"
-
- "loop"
- "while"
- "error"
-
- "do"
- "if"
- "else"
- "try"
- "catch"
- "match"
-
- "break"
- "continue"
- "return"
-
-] @keyword
-
-(hide_mod "hide" @keyword)
-(decl_use "use" @keyword)
-
-(ctrl_for
- "for" @keyword
- "in" @keyword
-)
-(overlay_list "list" @keyword)
-(overlay_hide "hide" @keyword)
-(overlay_new "new" @keyword)
-(overlay_use
- "use" @keyword
- "as" @keyword
-)
-(ctrl_error "make" @keyword)
-
-;;; ---
-;;; literals
-(val_number) @constant
-(val_duration
- unit: [
- "ns" "µs" "us" "ms" "sec" "min" "hr" "day" "wk"
- ] @variable
-)
-(val_filesize
- unit: [
- "b" "B"
-
- "kb" "kB" "Kb" "KB"
- "mb" "mB" "Mb" "MB"
- "gb" "gB" "Gb" "GB"
- "tb" "tB" "Tb" "TB"
- "pb" "pB" "Pb" "PB"
- "eb" "eB" "Eb" "EB"
- "zb" "zB" "Zb" "ZB"
-
- "kib" "kiB" "kIB" "kIb" "Kib" "KIb" "KIB"
- "mib" "miB" "mIB" "mIb" "Mib" "MIb" "MIB"
- "gib" "giB" "gIB" "gIb" "Gib" "GIb" "GIB"
- "tib" "tiB" "tIB" "tIb" "Tib" "TIb" "TIB"
- "pib" "piB" "pIB" "pIb" "Pib" "PIb" "PIB"
- "eib" "eiB" "eIB" "eIb" "Eib" "EIb" "EIB"
- "zib" "ziB" "zIB" "zIb" "Zib" "ZIb" "ZIB"
- ] @variable
-)
-(val_binary
- [
- "0b"
- "0o"
- "0x"
- ] @constant
- "[" @punctuation.bracket
- digit: [
- "," @punctuation.delimiter
- (hex_digit) @constant
- ]
- "]" @punctuation.bracket
-) @constant
-(val_bool) @constant.builtin
-(val_nothing) @constant.builtin
-(val_string) @string
-(val_date) @constant
-(inter_escape_sequence) @constant
-(escape_sequence) @constant
-(val_interpolated [
- "$\""
- "$\'"
- "\""
- "\'"
-] @string)
-(unescaped_interpolated_content) @string
-(escaped_interpolated_content) @string
-(expr_interpolated ["(" ")"] @variable)
-
-;;; ---
-;;; operators
-(expr_binary [
- "+"
- "-"
- "*"
- "/"
- "mod"
- "//"
- "++"
- "**"
- "=="
- "!="
- "<"
- "<="
- ">"
- ">="
- "=~"
- "!~"
- "and"
- "or"
- "xor"
- "bit-or"
- "bit-xor"
- "bit-and"
- "bit-shl"
- "bit-shr"
- "in"
- "not-in"
- "starts-with"
- "ends-with"
-] @operator)
-
-(expr_binary opr: ([
- "and"
- "or"
- "xor"
- "bit-or"
- "bit-xor"
- "bit-and"
- "bit-shl"
- "bit-shr"
- "in"
- "not-in"
- "starts-with"
- "ends-with"
-]) @keyword)
-
-(where_command [
- "+"
- "-"
- "*"
- "/"
- "mod"
- "//"
- "++"
- "**"
- "=="
- "!="
- "<"
- "<="
- ">"
- ">="
- "=~"
- "!~"
- "and"
- "or"
- "xor"
- "bit-or"
- "bit-xor"
- "bit-and"
- "bit-shl"
- "bit-shr"
- "in"
- "not-in"
- "starts-with"
- "ends-with"
-] @operator)
-
-(assignment [
- "="
- "+="
- "-="
- "*="
- "/="
- "++="
-] @operator)
-
-(expr_unary ["not" "-"] @operator)
-
-(val_range [
- ".."
- "..="
- "..<"
-] @operator)
-
-["=>" "=" "|"] @operator
-
-[
- "o>" "out>"
- "e>" "err>"
- "e+o>" "err+out>"
- "o+e>" "out+err>"
-] @special
-
-;;; ---
-;;; punctuation
-[
- ","
- ";"
-] @punctuation.delimiter
-
-(param_short_flag "-" @punctuation.delimiter)
-(param_long_flag ["--"] @punctuation.delimiter)
-(long_flag ["--"] @punctuation.delimiter)
-(param_rest "..." @punctuation.delimiter)
-(param_type [":"] @punctuation.special)
-(param_value ["="] @punctuation.special)
-(param_cmd ["@"] @punctuation.special)
-(param_opt ["?"] @punctuation.special)
-
-[
- "(" ")"
- "{" "}"
- "[" "]"
-] @punctuation.bracket
-
-(val_record
- (record_entry ":" @punctuation.delimiter))
-;;; ---
-;;; identifiers
-(param_rest
- name: (_) @variable)
-(param_opt
- name: (_) @variable)
-(parameter
- param_name: (_) @variable)
-(param_cmd
- (cmd_identifier) @string)
-(param_long_flag) @variable
-(param_short_flag) @variable
-
-(short_flag) @variable
-(long_flag) @variable
-
-(scope_pattern [(wild_card) @function])
-
-(cmd_identifier) @function
-
-(command
- "^" @punctuation.delimiter
- head: (_) @function
-)
-
-"where" @function
-
-(path
- ["." "?"] @punctuation.delimiter
-) @variable
-
-(val_variable
- "$" @operator
- [
- (identifier) @variable
- "in" @type.builtin
- "nu" @type.builtin
- "env" @type.builtin
- "nothing" @type.builtin
- ] ; If we have a special styling, use it here
-)
-;;; ---
-;;; types
-(flat_type) @type.builtin
-(list_type
- "list" @type
- ["<" ">"] @punctuation.bracket
-)
-(collection_type
- ["record" "table"] @type
- "<" @punctuation.bracket
- key: (_) @variable
- ["," ":"] @punctuation.delimiter
- ">" @punctuation.bracket
-)
-
-(shebang) @comment
-(comment) @comment
@@ -1,3 +0,0 @@
-(_ "[" "]" @end) @indent
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,136 +0,0 @@
-use anyhow::{anyhow, Result};
-
-use async_trait::async_trait;
-use collections::HashMap;
-
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use node_runtime::NodeRuntime;
-
-use smol::{fs, stream::StreamExt};
-use std::{
- any::Any,
- ffi::OsString,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::ResultExt;
-
-fn intelephense_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-pub struct IntelephenseVersion(String);
-
-pub struct IntelephenseLspAdapter {
- node: Arc<dyn NodeRuntime>,
-}
-
-impl IntelephenseLspAdapter {
- const SERVER_PATH: &'static str = "node_modules/intelephense/lib/intelephense.js";
-
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- Self { node }
- }
-}
-
-#[async_trait]
-impl LspAdapter for IntelephenseLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("intelephense".into())
- }
-
- fn short_name(&self) -> &'static str {
- "php"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _delegate: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- Ok(Box::new(IntelephenseVersion(
- self.node.npm_package_latest_version("intelephense").await?,
- )) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _delegate: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<IntelephenseVersion>().unwrap();
- let server_path = container_dir.join(Self::SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(&container_dir, &[("intelephense", version.0.as_str())])
- .await?;
- }
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: intelephense_server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn label_for_completion(
- &self,
- _item: &lsp::CompletionItem,
- _language: &Arc<language::Language>,
- ) -> Option<language::CodeLabel> {
- None
- }
-
- async fn initialization_options(&self) -> Option<serde_json::Value> {
- None
- }
- async fn language_ids(&self) -> HashMap<String, String> {
- HashMap::from_iter([("PHP".into(), "php".into())])
- }
-}
-
-async fn get_cached_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last_version_dir = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_dir() {
- last_version_dir = Some(entry.path());
- }
- }
- let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
- let server_path = last_version_dir.join(IntelephenseLspAdapter::SERVER_PATH);
- if server_path.exists() {
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: intelephense_server_binary_arguments(&server_path),
- })
- } else {
- Err(anyhow!(
- "missing executable in directory {:?}",
- last_version_dir
- ))
- }
- })()
- .await
- .log_err()
-}
@@ -1,14 +0,0 @@
-name = "PHP"
-path_suffixes = ["php"]
-first_line_pattern = '^#!.*php'
-line_comment = "// "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
-]
-collapsed_placeholder = "/* ... */"
-word_characters = ["$"]
-scope_opt_in_language_servers = ["tailwindcss-language-server"]
@@ -1,36 +0,0 @@
-(
- (comment)* @context
- .
- [
- (function_definition
- "function" @name
- name: (_) @name
- body: (_
- "{" @keep
- "}" @keep) @collapse
- )
-
- (trait_declaration
- "trait" @name
- name: (_) @name)
-
- (method_declaration
- "function" @name
- name: (_) @name
- body: (_
- "{" @keep
- "}" @keep) @collapse
- )
-
- (interface_declaration
- "interface" @name
- name: (_) @name
- )
-
- (enum_declaration
- "enum" @name
- name: (_) @name
- )
-
- ] @item
- )
@@ -1,123 +0,0 @@
-(php_tag) @tag
-"?>" @tag
-
-; Types
-
-(primitive_type) @type.builtin
-(cast_type) @type.builtin
-(named_type (name) @type) @type
-(named_type (qualified_name) @type) @type
-
-; Functions
-
-(array_creation_expression "array" @function.builtin)
-(list_literal "list" @function.builtin)
-
-(method_declaration
- name: (name) @function.method)
-
-(function_call_expression
- function: [(qualified_name (name)) (name)] @function)
-
-(scoped_call_expression
- name: (name) @function)
-
-(member_call_expression
- name: (name) @function.method)
-
-(function_definition
- name: (name) @function)
-
-; Member
-
-(property_element
- (variable_name) @property)
-
-(member_access_expression
- name: (variable_name (name)) @property)
-(member_access_expression
- name: (name) @property)
-
-; Variables
-
-(relative_scope) @variable.builtin
-
-((name) @constant
- (#match? @constant "^_?[A-Z][A-Z\\d_]+$"))
-((name) @constant.builtin
- (#match? @constant.builtin "^__[A-Z][A-Z\d_]+__$"))
-
-((name) @constructor
- (#match? @constructor "^[A-Z]"))
-
-((name) @variable.builtin
- (#eq? @variable.builtin "this"))
-
-(variable_name) @variable
-
-; Basic tokens
-[
- (string)
- (string_value)
- (encapsed_string)
- (heredoc)
- (heredoc_body)
- (nowdoc_body)
-] @string
-(boolean) @constant.builtin
-(null) @constant.builtin
-(integer) @number
-(float) @number
-(comment) @comment
-
-"$" @operator
-
-; Keywords
-
-"abstract" @keyword
-"as" @keyword
-"break" @keyword
-"case" @keyword
-"catch" @keyword
-"class" @keyword
-"const" @keyword
-"continue" @keyword
-"declare" @keyword
-"default" @keyword
-"do" @keyword
-"echo" @keyword
-"else" @keyword
-"elseif" @keyword
-"enum" @keyword
-"enddeclare" @keyword
-"endforeach" @keyword
-"endif" @keyword
-"endswitch" @keyword
-"endwhile" @keyword
-"extends" @keyword
-"final" @keyword
-"finally" @keyword
-"foreach" @keyword
-"function" @keyword
-"global" @keyword
-"if" @keyword
-"implements" @keyword
-"include_once" @keyword
-"include" @keyword
-"insteadof" @keyword
-"interface" @keyword
-"namespace" @keyword
-"new" @keyword
-"private" @keyword
-"protected" @keyword
-"public" @keyword
-"require_once" @keyword
-"require" @keyword
-"return" @keyword
-"static" @keyword
-"switch" @keyword
-"throw" @keyword
-"trait" @keyword
-"try" @keyword
-"use" @keyword
-"while" @keyword
@@ -1,3 +0,0 @@
-((text) @content
- (#set! "language" "html")
- (#set! "combined"))
@@ -1,29 +0,0 @@
-(class_declaration
- "class" @context
- name: (name) @name
- ) @item
-
-(function_definition
- "function" @context
- name: (_) @name
- ) @item
-
-(method_declaration
- "function" @context
- name: (_) @name
- ) @item
-
-(interface_declaration
- "interface" @context
- name: (_) @name
- ) @item
-
-(enum_declaration
- "enum" @context
- name: (_) @name
- ) @item
-
-(trait_declaration
- "trait" @context
- name: (_) @name
- ) @item
@@ -1,40 +0,0 @@
-(namespace_definition
- name: (namespace_name) @name) @module
-
-(interface_declaration
- name: (name) @name) @definition.interface
-
-(trait_declaration
- name: (name) @name) @definition.interface
-
-(class_declaration
- name: (name) @name) @definition.class
-
-(class_interface_clause [(name) (qualified_name)] @name) @impl
-
-(property_declaration
- (property_element (variable_name (name) @name))) @definition.field
-
-(function_definition
- name: (name) @name) @definition.function
-
-(method_declaration
- name: (name) @name) @definition.function
-
-(object_creation_expression
- [
- (qualified_name (name) @name)
- (variable_name (name) @name)
- ]) @reference.class
-
-(function_call_expression
- function: [
- (qualified_name (name) @name)
- (variable_name (name)) @name
- ]) @reference.call
-
-(scoped_call_expression
- name: (name) @name) @reference.call
-
-(member_call_expression
- name: (name) @name) @reference.call
@@ -1,296 +0,0 @@
-use anyhow::Result;
-use async_trait::async_trait;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use node_runtime::NodeRuntime;
-use smol::fs;
-use std::{
- any::Any,
- ffi::OsString,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::ResultExt;
-
-const SERVER_PATH: &'static str = "node_modules/pyright/langserver.index.js";
-
-fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-pub struct PythonLspAdapter {
- node: Arc<dyn NodeRuntime>,
-}
-
-impl PythonLspAdapter {
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- PythonLspAdapter { node }
- }
-}
-
-#[async_trait]
-impl LspAdapter for PythonLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("pyright".into())
- }
-
- fn short_name(&self) -> &'static str {
- "pyright"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Any + Send>> {
- Ok(Box::new(self.node.npm_package_latest_version("pyright").await?) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<String>().unwrap();
- let server_path = container_dir.join(SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(&container_dir, &[("pyright", version.as_str())])
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn process_completion(&self, item: &mut lsp::CompletionItem) {
- // Pyright assigns each completion item a `sortText` of the form `XX.YYYY.name`.
- // Where `XX` is the sorting category, `YYYY` is based on most recent usage,
- // and `name` is the symbol name itself.
- //
- // Because the the symbol name is included, there generally are not ties when
- // sorting by the `sortText`, so the symbol's fuzzy match score is not taken
- // into account. Here, we remove the symbol name from the sortText in order
- // to allow our own fuzzy score to be used to break ties.
- //
- // see https://github.com/microsoft/pyright/blob/95ef4e103b9b2f129c9320427e51b73ea7cf78bd/packages/pyright-internal/src/languageService/completionProvider.ts#LL2873
- let Some(sort_text) = &mut item.sort_text else {
- return;
- };
- let mut parts = sort_text.split('.');
- let Some(first) = parts.next() else { return };
- let Some(second) = parts.next() else { return };
- let Some(_) = parts.next() else { return };
- sort_text.replace_range(first.len() + second.len() + 1.., "");
- }
-
- async fn label_for_completion(
- &self,
- item: &lsp::CompletionItem,
- language: &Arc<language::Language>,
- ) -> Option<language::CodeLabel> {
- let label = &item.label;
- let grammar = language.grammar()?;
- let highlight_id = match item.kind? {
- lsp::CompletionItemKind::METHOD => grammar.highlight_id_for_name("function.method")?,
- lsp::CompletionItemKind::FUNCTION => grammar.highlight_id_for_name("function")?,
- lsp::CompletionItemKind::CLASS => grammar.highlight_id_for_name("type")?,
- lsp::CompletionItemKind::CONSTANT => grammar.highlight_id_for_name("constant")?,
- _ => return None,
- };
- Some(language::CodeLabel {
- text: label.clone(),
- runs: vec![(0..label.len(), highlight_id)],
- filter_range: 0..label.len(),
- })
- }
-
- async fn label_for_symbol(
- &self,
- name: &str,
- kind: lsp::SymbolKind,
- language: &Arc<language::Language>,
- ) -> Option<language::CodeLabel> {
- let (text, filter_range, display_range) = match kind {
- lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
- let text = format!("def {}():\n", name);
- let filter_range = 4..4 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::CLASS => {
- let text = format!("class {}:", name);
- let filter_range = 6..6 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::CONSTANT => {
- let text = format!("{} = 0", name);
- let filter_range = 0..name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- _ => return None,
- };
-
- Some(language::CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
- filter_range,
- })
- }
-}
-
-async fn get_cached_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- let server_path = container_dir.join(SERVER_PATH);
- if server_path.exists() {
- Some(LanguageServerBinary {
- path: node.binary_path().await.log_err()?,
- arguments: server_binary_arguments(&server_path),
- })
- } else {
- log::error!("missing executable in directory {:?}", server_path);
- None
- }
-}
-
-#[cfg(test)]
-mod tests {
- use gpui::{Context, ModelContext, TestAppContext};
- use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer};
- use settings::SettingsStore;
- use std::num::NonZeroU32;
-
- #[gpui::test]
- async fn test_python_autoindent(cx: &mut TestAppContext) {
- // cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX);
- let language =
- crate::languages::language("python", tree_sitter_python::language(), None).await;
- cx.update(|cx| {
- let test_settings = SettingsStore::test(cx);
- cx.set_global(test_settings);
- language::init(cx);
- cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<AllLanguageSettings>(cx, |s| {
- s.defaults.tab_size = NonZeroU32::new(2);
- });
- });
- });
-
- cx.new_model(|cx| {
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), "").with_language(language, cx);
- let append = |buffer: &mut Buffer, text: &str, cx: &mut ModelContext<Buffer>| {
- let ix = buffer.len();
- buffer.edit([(ix..ix, text)], Some(AutoindentMode::EachLine), cx);
- };
-
- // indent after "def():"
- append(&mut buffer, "def a():\n", cx);
- assert_eq!(buffer.text(), "def a():\n ");
-
- // preserve indent after blank line
- append(&mut buffer, "\n ", cx);
- assert_eq!(buffer.text(), "def a():\n \n ");
-
- // indent after "if"
- append(&mut buffer, "if a:\n ", cx);
- assert_eq!(buffer.text(), "def a():\n \n if a:\n ");
-
- // preserve indent after statement
- append(&mut buffer, "b()\n", cx);
- assert_eq!(buffer.text(), "def a():\n \n if a:\n b()\n ");
-
- // preserve indent after statement
- append(&mut buffer, "else", cx);
- assert_eq!(buffer.text(), "def a():\n \n if a:\n b()\n else");
-
- // dedent "else""
- append(&mut buffer, ":", cx);
- assert_eq!(buffer.text(), "def a():\n \n if a:\n b()\n else:");
-
- // indent lines after else
- append(&mut buffer, "\n", cx);
- assert_eq!(
- buffer.text(),
- "def a():\n \n if a:\n b()\n else:\n "
- );
-
- // indent after an open paren. the closing paren is not indented
- // because there is another token before it on the same line.
- append(&mut buffer, "foo(\n1)", cx);
- assert_eq!(
- buffer.text(),
- "def a():\n \n if a:\n b()\n else:\n foo(\n 1)"
- );
-
- // dedent the closing paren if it is shifted to the beginning of the line
- let argument_ix = buffer.text().find('1').unwrap();
- buffer.edit(
- [(argument_ix..argument_ix + 1, "")],
- Some(AutoindentMode::EachLine),
- cx,
- );
- assert_eq!(
- buffer.text(),
- "def a():\n \n if a:\n b()\n else:\n foo(\n )"
- );
-
- // preserve indent after the close paren
- append(&mut buffer, "\n", cx);
- assert_eq!(
- buffer.text(),
- "def a():\n \n if a:\n b()\n else:\n foo(\n )\n "
- );
-
- // manually outdent the last line
- let end_whitespace_ix = buffer.len() - 4;
- buffer.edit(
- [(end_whitespace_ix..buffer.len(), "")],
- Some(AutoindentMode::EachLine),
- cx,
- );
- assert_eq!(
- buffer.text(),
- "def a():\n \n if a:\n b()\n else:\n foo(\n )\n"
- );
-
- // preserve the newly reduced indentation on the next newline
- append(&mut buffer, "\n", cx);
- assert_eq!(
- buffer.text(),
- "def a():\n \n if a:\n b()\n else:\n foo(\n )\n\n"
- );
-
- // reset to a simple if statement
- buffer.edit([(0..buffer.len(), "if a:\n b(\n )")], None, cx);
-
- // dedent "else" on the line after a closing paren
- append(&mut buffer, "\n else:\n", cx);
- assert_eq!(buffer.text(), "if a:\n b(\n )\nelse:\n ");
-
- buffer
- });
- }
-}
@@ -1,3 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
@@ -1,16 +0,0 @@
-name = "Python"
-path_suffixes = ["py", "pyi", "mpy"]
-first_line_pattern = '^#!.*\bpython[0-9.]*\b'
-line_comment = "# "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
- { start = "'", end = "'", close = false, newline = false, not_in = ["string"] },
-]
-
-auto_indent_using_last_non_empty_line = false
-increase_indent_pattern = ":\\s*$"
-decrease_indent_pattern = "^\\s*(else|elif|except|finally)\\b.*:"
@@ -1,9 +0,0 @@
-(class_definition
- "class" @context
- name: (identifier) @name
- ) @item
-
-(function_definition
- "async"? @context
- "def" @context
- name: (_) @name) @item
@@ -1,125 +0,0 @@
-(attribute attribute: (identifier) @property)
-(type (identifier) @type)
-
-; Function calls
-
-(decorator) @function
-
-(call
- function: (attribute attribute: (identifier) @function.method))
-(call
- function: (identifier) @function)
-
-; Function definitions
-
-(function_definition
- name: (identifier) @function)
-
-; Identifier naming conventions
-
-((identifier) @type
- (#match? @type "^[A-Z]"))
-
-((identifier) @constant
- (#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
-
-; Builtin functions
-
-((call
- function: (identifier) @function.builtin)
- (#match?
- @function.builtin
- "^(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|exec|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|__import__)$"))
-
-; Literals
-
-[
- (none)
- (true)
- (false)
-] @constant.builtin
-
-[
- (integer)
- (float)
-] @number
-
-(comment) @comment
-(string) @string
-(escape_sequence) @escape
-
-(interpolation
- "{" @punctuation.special
- "}" @punctuation.special) @embedded
-
-[
- "-"
- "-="
- "!="
- "*"
- "**"
- "**="
- "*="
- "/"
- "//"
- "//="
- "/="
- "&"
- "%"
- "%="
- "^"
- "+"
- "->"
- "+="
- "<"
- "<<"
- "<="
- "<>"
- "="
- ":="
- "=="
- ">"
- ">="
- ">>"
- "|"
- "~"
- "and"
- "in"
- "is"
- "not"
- "or"
-] @operator
-
-[
- "as"
- "assert"
- "async"
- "await"
- "break"
- "class"
- "continue"
- "def"
- "del"
- "elif"
- "else"
- "except"
- "exec"
- "finally"
- "for"
- "from"
- "global"
- "if"
- "import"
- "lambda"
- "nonlocal"
- "pass"
- "print"
- "raise"
- "return"
- "try"
- "while"
- "with"
- "yield"
- "match"
- "case"
-] @keyword
@@ -1,3 +0,0 @@
-(_ "[" "]" @end) @indent
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,9 +0,0 @@
-(class_definition
- "class" @context
- name: (identifier) @name
- ) @item
-
-(function_definition
- "async"? @context
- "def" @context
- name: (_) @name) @item
@@ -1,2 +0,0 @@
-(comment) @comment
-(string) @string
@@ -1,3 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
@@ -1,9 +0,0 @@
-name = "Racket"
-path_suffixes = ["rkt"]
-line_comment = "; "
-autoclose_before = "])"
-brackets = [
- { start = "[", end = "]", close = true, newline = false },
- { start = "(", end = ")", close = true, newline = false },
- { start = "\"", end = "\"", close = true, newline = false },
-]
@@ -1,39 +0,0 @@
-["(" ")" "[" "]" "{" "}"] @punctuation.bracket
-
-[(string)
- (here_string)
- (byte_string)] @string
-(regex) @string.regex
-(escape_sequence) @escape
-
-[(comment)
- (block_comment)
- (sexp_comment)] @comment
-
-(symbol) @variable
-
-(number) @number
-(character) @constant.builtin
-(boolean) @constant.builtin
-(keyword) @constant
-(quote . (symbol)) @constant
-
-(extension) @keyword
-(lang_name) @variable.special
-
-((symbol) @operator
- (#match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$"))
-
-(list
- .
- (symbol) @function)
-
-(list
- .
- (symbol) @keyword
- (#match? @keyword
@@ -1,3 +0,0 @@
-(_ "[" "]") @indent
-(_ "{" "}") @indent
-(_ "(" ")") @indent
@@ -1,10 +0,0 @@
-(list
- .
- (symbol) @start-symbol @context
- .
- [
- (symbol) @name
- (list . (symbol) @name)
- ]
- (#match? @start-symbol "^define")
-) @item
@@ -1,160 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use std::{any::Any, path::PathBuf, sync::Arc};
-
-pub struct RubyLanguageServer;
-
-#[async_trait]
-impl LspAdapter for RubyLanguageServer {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("solargraph".into())
- }
-
- fn short_name(&self) -> &'static str {
- "solargraph"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Any + Send>> {
- Ok(Box::new(()))
- }
-
- async fn fetch_server_binary(
- &self,
- _version: Box<dyn 'static + Send + Any>,
- _container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- Err(anyhow!("solargraph must be installed manually"))
- }
-
- async fn cached_server_binary(
- &self,
- _: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- Some(LanguageServerBinary {
- path: "solargraph".into(),
- arguments: vec!["stdio".into()],
- })
- }
-
- fn can_be_reinstalled(&self) -> bool {
- false
- }
-
- async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
- None
- }
-
- async fn label_for_completion(
- &self,
- item: &lsp::CompletionItem,
- language: &Arc<language::Language>,
- ) -> Option<language::CodeLabel> {
- let label = &item.label;
- let grammar = language.grammar()?;
- let highlight_id = match item.kind? {
- lsp::CompletionItemKind::METHOD => grammar.highlight_id_for_name("function.method")?,
- lsp::CompletionItemKind::CONSTANT => grammar.highlight_id_for_name("constant")?,
- lsp::CompletionItemKind::CLASS | lsp::CompletionItemKind::MODULE => {
- grammar.highlight_id_for_name("type")?
- }
- lsp::CompletionItemKind::KEYWORD => {
- if label.starts_with(':') {
- grammar.highlight_id_for_name("string.special.symbol")?
- } else {
- grammar.highlight_id_for_name("keyword")?
- }
- }
- lsp::CompletionItemKind::VARIABLE => {
- if label.starts_with('@') {
- grammar.highlight_id_for_name("property")?
- } else {
- return None;
- }
- }
- _ => return None,
- };
- Some(language::CodeLabel {
- text: label.clone(),
- runs: vec![(0..label.len(), highlight_id)],
- filter_range: 0..label.len(),
- })
- }
-
- async fn label_for_symbol(
- &self,
- label: &str,
- kind: lsp::SymbolKind,
- language: &Arc<language::Language>,
- ) -> Option<language::CodeLabel> {
- let grammar = language.grammar()?;
- match kind {
- lsp::SymbolKind::METHOD => {
- let mut parts = label.split('#');
- let classes = parts.next()?;
- let method = parts.next()?;
- if parts.next().is_some() {
- return None;
- }
-
- let class_id = grammar.highlight_id_for_name("type")?;
- let method_id = grammar.highlight_id_for_name("function.method")?;
-
- let mut ix = 0;
- let mut runs = Vec::new();
- for (i, class) in classes.split("::").enumerate() {
- if i > 0 {
- ix += 2;
- }
- let end_ix = ix + class.len();
- runs.push((ix..end_ix, class_id));
- ix = end_ix;
- }
-
- ix += 1;
- let end_ix = ix + method.len();
- runs.push((ix..end_ix, method_id));
- Some(language::CodeLabel {
- text: label.to_string(),
- runs,
- filter_range: 0..label.len(),
- })
- }
- lsp::SymbolKind::CONSTANT => {
- let constant_id = grammar.highlight_id_for_name("constant")?;
- Some(language::CodeLabel {
- text: label.to_string(),
- runs: vec![(0..label.len(), constant_id)],
- filter_range: 0..label.len(),
- })
- }
- lsp::SymbolKind::CLASS | lsp::SymbolKind::MODULE => {
- let class_id = grammar.highlight_id_for_name("type")?;
-
- let mut ix = 0;
- let mut runs = Vec::new();
- for (i, class) in label.split("::").enumerate() {
- if i > 0 {
- ix += "::".len();
- }
- let end_ix = ix + class.len();
- runs.push((ix..end_ix, class_id));
- ix = end_ix;
- }
-
- Some(language::CodeLabel {
- text: label.to_string(),
- runs,
- filter_range: 0..label.len(),
- })
- }
- _ => return None,
- }
- }
-}
@@ -1,14 +0,0 @@
-("[" @open "]" @close)
-("{" @open "}" @close)
-("\"" @open "\"" @close)
-("do" @open "end" @close)
-
-(block_parameters "|" @open "|" @close)
-(interpolation "#{" @open "}" @close)
-
-(if "if" @open "end" @close)
-(unless "unless" @open "end" @close)
-(begin "begin" @open "end" @close)
-(module "module" @open "end" @close)
-(_ . "def" @open "end" @close)
-(_ . "class" @open "end" @close)
@@ -1,13 +0,0 @@
-name = "Ruby"
-path_suffixes = ["rb", "Gemfile"]
-first_line_pattern = '^#!.*\bruby\b'
-line_comment = "# "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
-]
-collapsed_placeholder = "# ..."
@@ -1,22 +0,0 @@
-(
- (comment)* @context
- .
- [
- (module
- "module" @name
- name: (_) @name)
- (method
- "def" @name
- name: (_) @name
- body: (body_statement) @collapse)
- (class
- "class" @name
- name: (_) @name)
- (singleton_method
- "def" @name
- object: (_) @name
- "." @name
- name: (_) @name
- body: (body_statement) @collapse)
- ] @item
- )
@@ -1,181 +0,0 @@
-; Keywords
-
-[
- "alias"
- "and"
- "begin"
- "break"
- "case"
- "class"
- "def"
- "do"
- "else"
- "elsif"
- "end"
- "ensure"
- "for"
- "if"
- "in"
- "module"
- "next"
- "or"
- "rescue"
- "retry"
- "return"
- "then"
- "unless"
- "until"
- "when"
- "while"
- "yield"
-] @keyword
-
-(identifier) @variable
-
-((identifier) @keyword
- (#match? @keyword "^(private|protected|public)$"))
-
-; Function calls
-
-((identifier) @function.method.builtin
- (#eq? @function.method.builtin "require"))
-
-"defined?" @function.method.builtin
-
-(call
- method: [(identifier) (constant)] @function.method)
-
-; Function definitions
-
-(alias (identifier) @function.method)
-(setter (identifier) @function.method)
-(method name: [(identifier) (constant)] @function.method)
-(singleton_method name: [(identifier) (constant)] @function.method)
-
-; Identifiers
-
-[
- (class_variable)
- (instance_variable)
-] @property
-
-((identifier) @constant.builtin
- (#match? @constant.builtin "^__(FILE|LINE|ENCODING)__$"))
-
-(file) @constant.builtin
-(line) @constant.builtin
-(encoding) @constant.builtin
-
-(hash_splat_nil
- "**" @operator
-) @constant.builtin
-
-((constant) @constant
- (#match? @constant "^[A-Z\\d_]+$"))
-
-(constant) @type
-
-(self) @variable.special
-(super) @variable.special
-
-; Literals
-
-[
- (string)
- (bare_string)
- (subshell)
- (heredoc_body)
- (heredoc_beginning)
-] @string
-
-[
- (simple_symbol)
- (delimited_symbol)
- (hash_key_symbol)
- (bare_symbol)
-] @string.special.symbol
-
-(regex) @string.regex
-(escape_sequence) @escape
-
-[
- (integer)
- (float)
-] @number
-
-[
- (nil)
- (true)
- (false)
-] @constant.builtin
-
-(comment) @comment
-
-; Operators
-
-[
- "!"
- "~"
- "+"
- "-"
- "**"
- "*"
- "/"
- "%"
- "<<"
- ">>"
- "&"
- "|"
- "^"
- ">"
- "<"
- "<="
- ">="
- "=="
- "!="
- "=~"
- "!~"
- "<=>"
- "||"
- "&&"
- ".."
- "..."
- "="
- "**="
- "*="
- "/="
- "%="
- "+="
- "-="
- "<<="
- ">>="
- "&&="
- "&="
- "||="
- "|="
- "^="
- "=>"
- "->"
- (operator)
-] @operator
-
-[
- ","
- ";"
- "."
-] @punctuation.delimiter
-
-[
- "("
- ")"
- "["
- "]"
- "{"
- "}"
- "%w("
- "%i("
-] @punctuation.bracket
-
-(interpolation
- "#{" @punctuation.special
- "}" @punctuation.special) @embedded
@@ -1,17 +0,0 @@
-(method "end" @end) @indent
-(class "end" @end) @indent
-(module "end" @end) @indent
-(begin "end" @end) @indent
-(do_block "end" @end) @indent
-
-(then) @indent
-(call) @indent
-
-(ensure) @outdent
-(rescue) @outdent
-(else) @outdent
-
-
-(_ "[" "]" @end) @indent
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,17 +0,0 @@
-(class
- "class" @context
- name: (_) @name) @item
-
-(method
- "def" @context
- name: (_) @name) @item
-
-(singleton_method
- "def" @context
- object: (_) @context
- "." @context
- name: (_) @name) @item
-
-(module
- "module" @context
- name: (_) @name) @item
@@ -1,2 +0,0 @@
-(comment) @comment
-(string) @string
@@ -1,568 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_compression::futures::bufread::GzipDecoder;
-use async_trait::async_trait;
-use futures::{io::BufReader, StreamExt};
-pub use language::*;
-use lazy_static::lazy_static;
-use lsp::LanguageServerBinary;
-use regex::Regex;
-use smol::fs::{self, File};
-use std::{any::Any, borrow::Cow, env::consts, path::PathBuf, str, sync::Arc};
-use util::{
- fs::remove_matching,
- github::{latest_github_release, GitHubLspBinaryVersion},
- ResultExt,
-};
-
-pub struct RustLspAdapter;
-
-#[async_trait]
-impl LspAdapter for RustLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("rust-analyzer".into())
- }
-
- fn short_name(&self) -> &'static str {
- "rust"
- }
-
- async fn fetch_latest_server_version(
- &self,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- let release =
- latest_github_release("rust-analyzer/rust-analyzer", false, delegate.http_client())
- .await?;
- let asset_name = format!("rust-analyzer-{}-apple-darwin.gz", consts::ARCH);
- let asset = release
- .assets
- .iter()
- .find(|asset| asset.name == asset_name)
- .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?;
- Ok(Box::new(GitHubLspBinaryVersion {
- name: release.name,
- url: asset.browser_download_url.clone(),
- }))
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
- let destination_path = container_dir.join(format!("rust-analyzer-{}", version.name));
-
- if fs::metadata(&destination_path).await.is_err() {
- let mut response = delegate
- .http_client()
- .get(&version.url, Default::default(), true)
- .await
- .map_err(|err| anyhow!("error downloading release: {}", err))?;
- let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
- let mut file = File::create(&destination_path).await?;
- futures::io::copy(decompressed_bytes, &mut file).await?;
- fs::set_permissions(
- &destination_path,
- <fs::Permissions as fs::unix::PermissionsExt>::from_mode(0o755),
- )
- .await?;
-
- remove_matching(&container_dir, |entry| entry != destination_path).await;
- }
-
- Ok(LanguageServerBinary {
- path: destination_path,
- arguments: Default::default(),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir)
- .await
- .map(|mut binary| {
- binary.arguments = vec!["--help".into()];
- binary
- })
- }
-
- async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
- vec!["rustc".into()]
- }
-
- async fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
- Some("rust-analyzer/flycheck".into())
- }
-
- fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
- lazy_static! {
- static ref REGEX: Regex = Regex::new("(?m)`([^`]+)\n`$").unwrap();
- }
-
- for diagnostic in &mut params.diagnostics {
- for message in diagnostic
- .related_information
- .iter_mut()
- .flatten()
- .map(|info| &mut info.message)
- .chain([&mut diagnostic.message])
- {
- if let Cow::Owned(sanitized) = REGEX.replace_all(message, "`$1`") {
- *message = sanitized;
- }
- }
- }
- }
-
- async fn label_for_completion(
- &self,
- completion: &lsp::CompletionItem,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- match completion.kind {
- Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => {
- let detail = completion.detail.as_ref().unwrap();
- let name = &completion.label;
- let text = format!("{}: {}", name, detail);
- let source = Rope::from(format!("struct S {{ {} }}", text).as_str());
- let runs = language.highlight_text(&source, 11..11 + text.len());
- return Some(CodeLabel {
- text,
- runs,
- filter_range: 0..name.len(),
- });
- }
- Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE)
- if completion.detail.is_some()
- && completion.insert_text_format != Some(lsp::InsertTextFormat::SNIPPET) =>
- {
- let detail = completion.detail.as_ref().unwrap();
- let name = &completion.label;
- let text = format!("{}: {}", name, detail);
- let source = Rope::from(format!("let {} = ();", text).as_str());
- let runs = language.highlight_text(&source, 4..4 + text.len());
- return Some(CodeLabel {
- text,
- runs,
- filter_range: 0..name.len(),
- });
- }
- Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD)
- if completion.detail.is_some() =>
- {
- lazy_static! {
- static ref REGEX: Regex = Regex::new("\\(…?\\)").unwrap();
- }
- let detail = completion.detail.as_ref().unwrap();
- const FUNCTION_PREFIXES: [&'static str; 2] = ["async fn", "fn"];
- let prefix = FUNCTION_PREFIXES
- .iter()
- .find_map(|prefix| detail.strip_prefix(*prefix).map(|suffix| (prefix, suffix)));
- // fn keyword should be followed by opening parenthesis.
- if let Some((prefix, suffix)) = prefix {
- if suffix.starts_with('(') {
- let text = REGEX.replace(&completion.label, suffix).to_string();
- let source = Rope::from(format!("{prefix} {} {{}}", text).as_str());
- let run_start = prefix.len() + 1;
- let runs =
- language.highlight_text(&source, run_start..run_start + text.len());
- return Some(CodeLabel {
- filter_range: 0..completion.label.find('(').unwrap_or(text.len()),
- text,
- runs,
- });
- }
- }
- }
- Some(kind) => {
- let highlight_name = match kind {
- lsp::CompletionItemKind::STRUCT
- | lsp::CompletionItemKind::INTERFACE
- | lsp::CompletionItemKind::ENUM => Some("type"),
- lsp::CompletionItemKind::ENUM_MEMBER => Some("variant"),
- lsp::CompletionItemKind::KEYWORD => Some("keyword"),
- lsp::CompletionItemKind::VALUE | lsp::CompletionItemKind::CONSTANT => {
- Some("constant")
- }
- _ => None,
- };
- let highlight_id = language.grammar()?.highlight_id_for_name(highlight_name?)?;
- let mut label = CodeLabel::plain(completion.label.clone(), None);
- label.runs.push((
- 0..label.text.rfind('(').unwrap_or(label.text.len()),
- highlight_id,
- ));
- return Some(label);
- }
- _ => {}
- }
- None
- }
-
- async fn label_for_symbol(
- &self,
- name: &str,
- kind: lsp::SymbolKind,
- language: &Arc<Language>,
- ) -> Option<CodeLabel> {
- let (text, filter_range, display_range) = match kind {
- lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
- let text = format!("fn {} () {{}}", name);
- let filter_range = 3..3 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::STRUCT => {
- let text = format!("struct {} {{}}", name);
- let filter_range = 7..7 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::ENUM => {
- let text = format!("enum {} {{}}", name);
- let filter_range = 5..5 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::INTERFACE => {
- let text = format!("trait {} {{}}", name);
- let filter_range = 6..6 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::CONSTANT => {
- let text = format!("const {}: () = ();", name);
- let filter_range = 6..6 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::MODULE => {
- let text = format!("mod {} {{}}", name);
- let filter_range = 4..4 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- lsp::SymbolKind::TYPE_PARAMETER => {
- let text = format!("type {} {{}}", name);
- let filter_range = 5..5 + name.len();
- let display_range = 0..filter_range.end;
- (text, filter_range, display_range)
- }
- _ => return None,
- };
-
- Some(CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
- filter_range,
- })
- }
-}
-
-async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- last = Some(entry?.path());
- }
-
- anyhow::Ok(LanguageServerBinary {
- path: last.ok_or_else(|| anyhow!("no cached binary"))?,
- arguments: Default::default(),
- })
- })()
- .await
- .log_err()
-}
-
-#[cfg(test)]
-mod tests {
- use std::num::NonZeroU32;
-
- use super::*;
- use crate::languages::language;
- use gpui::{Context, Hsla, TestAppContext};
- use language::language_settings::AllLanguageSettings;
- use settings::SettingsStore;
- use theme::SyntaxTheme;
-
- #[gpui::test]
- async fn test_process_rust_diagnostics() {
- let mut params = lsp::PublishDiagnosticsParams {
- uri: lsp::Url::from_file_path("/a").unwrap(),
- version: None,
- diagnostics: vec![
- // no newlines
- lsp::Diagnostic {
- message: "use of moved value `a`".to_string(),
- ..Default::default()
- },
- // newline at the end of a code span
- lsp::Diagnostic {
- message: "consider importing this struct: `use b::c;\n`".to_string(),
- ..Default::default()
- },
- // code span starting right after a newline
- lsp::Diagnostic {
- message: "cannot borrow `self.d` as mutable\n`self` is a `&` reference"
- .to_string(),
- ..Default::default()
- },
- ],
- };
- RustLspAdapter.process_diagnostics(&mut params);
-
- assert_eq!(params.diagnostics[0].message, "use of moved value `a`");
-
- // remove trailing newline from code span
- assert_eq!(
- params.diagnostics[1].message,
- "consider importing this struct: `use b::c;`"
- );
-
- // do not remove newline before the start of code span
- assert_eq!(
- params.diagnostics[2].message,
- "cannot borrow `self.d` as mutable\n`self` is a `&` reference"
- );
- }
-
- #[gpui::test]
- async fn test_rust_label_for_completion() {
- let language = language(
- "rust",
- tree_sitter_rust::language(),
- Some(Arc::new(RustLspAdapter)),
- )
- .await;
- let grammar = language.grammar().unwrap();
- let theme = SyntaxTheme::new_test([
- ("type", Hsla::default()),
- ("keyword", Hsla::default()),
- ("function", Hsla::default()),
- ("property", Hsla::default()),
- ]);
-
- language.set_theme(&theme);
-
- let highlight_function = grammar.highlight_id_for_name("function").unwrap();
- let highlight_type = grammar.highlight_id_for_name("type").unwrap();
- let highlight_keyword = grammar.highlight_id_for_name("keyword").unwrap();
- let highlight_field = grammar.highlight_id_for_name("property").unwrap();
-
- assert_eq!(
- language
- .label_for_completion(&lsp::CompletionItem {
- kind: Some(lsp::CompletionItemKind::FUNCTION),
- label: "hello(…)".to_string(),
- detail: Some("fn(&mut Option<T>) -> Vec<T>".to_string()),
- ..Default::default()
- })
- .await,
- Some(CodeLabel {
- text: "hello(&mut Option<T>) -> Vec<T>".to_string(),
- filter_range: 0..5,
- runs: vec![
- (0..5, highlight_function),
- (7..10, highlight_keyword),
- (11..17, highlight_type),
- (18..19, highlight_type),
- (25..28, highlight_type),
- (29..30, highlight_type),
- ],
- })
- );
- assert_eq!(
- language
- .label_for_completion(&lsp::CompletionItem {
- kind: Some(lsp::CompletionItemKind::FUNCTION),
- label: "hello(…)".to_string(),
- detail: Some("async fn(&mut Option<T>) -> Vec<T>".to_string()),
- ..Default::default()
- })
- .await,
- Some(CodeLabel {
- text: "hello(&mut Option<T>) -> Vec<T>".to_string(),
- filter_range: 0..5,
- runs: vec![
- (0..5, highlight_function),
- (7..10, highlight_keyword),
- (11..17, highlight_type),
- (18..19, highlight_type),
- (25..28, highlight_type),
- (29..30, highlight_type),
- ],
- })
- );
- assert_eq!(
- language
- .label_for_completion(&lsp::CompletionItem {
- kind: Some(lsp::CompletionItemKind::FIELD),
- label: "len".to_string(),
- detail: Some("usize".to_string()),
- ..Default::default()
- })
- .await,
- Some(CodeLabel {
- text: "len: usize".to_string(),
- filter_range: 0..3,
- runs: vec![(0..3, highlight_field), (5..10, highlight_type),],
- })
- );
-
- assert_eq!(
- language
- .label_for_completion(&lsp::CompletionItem {
- kind: Some(lsp::CompletionItemKind::FUNCTION),
- label: "hello(…)".to_string(),
- detail: Some("fn(&mut Option<T>) -> Vec<T>".to_string()),
- ..Default::default()
- })
- .await,
- Some(CodeLabel {
- text: "hello(&mut Option<T>) -> Vec<T>".to_string(),
- filter_range: 0..5,
- runs: vec![
- (0..5, highlight_function),
- (7..10, highlight_keyword),
- (11..17, highlight_type),
- (18..19, highlight_type),
- (25..28, highlight_type),
- (29..30, highlight_type),
- ],
- })
- );
- }
-
- #[gpui::test]
- async fn test_rust_label_for_symbol() {
- let language = language(
- "rust",
- tree_sitter_rust::language(),
- Some(Arc::new(RustLspAdapter)),
- )
- .await;
- let grammar = language.grammar().unwrap();
- let theme = SyntaxTheme::new_test([
- ("type", Hsla::default()),
- ("keyword", Hsla::default()),
- ("function", Hsla::default()),
- ("property", Hsla::default()),
- ]);
-
- language.set_theme(&theme);
-
- let highlight_function = grammar.highlight_id_for_name("function").unwrap();
- let highlight_type = grammar.highlight_id_for_name("type").unwrap();
- let highlight_keyword = grammar.highlight_id_for_name("keyword").unwrap();
-
- assert_eq!(
- language
- .label_for_symbol("hello", lsp::SymbolKind::FUNCTION)
- .await,
- Some(CodeLabel {
- text: "fn hello".to_string(),
- filter_range: 3..8,
- runs: vec![(0..2, highlight_keyword), (3..8, highlight_function)],
- })
- );
-
- assert_eq!(
- language
- .label_for_symbol("World", lsp::SymbolKind::TYPE_PARAMETER)
- .await,
- Some(CodeLabel {
- text: "type World".to_string(),
- filter_range: 5..10,
- runs: vec![(0..4, highlight_keyword), (5..10, highlight_type)],
- })
- );
- }
-
- #[gpui::test]
- async fn test_rust_autoindent(cx: &mut TestAppContext) {
- // cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX);
- cx.update(|cx| {
- let test_settings = SettingsStore::test(cx);
- cx.set_global(test_settings);
- language::init(cx);
- cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<AllLanguageSettings>(cx, |s| {
- s.defaults.tab_size = NonZeroU32::new(2);
- });
- });
- });
-
- let language = crate::languages::language("rust", tree_sitter_rust::language(), None).await;
-
- cx.new_model(|cx| {
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), "").with_language(language, cx);
-
- // indent between braces
- buffer.set_text("fn a() {}", cx);
- let ix = buffer.len() - 1;
- buffer.edit([(ix..ix, "\n\n")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(buffer.text(), "fn a() {\n \n}");
-
- // indent between braces, even after empty lines
- buffer.set_text("fn a() {\n\n\n}", cx);
- let ix = buffer.len() - 2;
- buffer.edit([(ix..ix, "\n")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(buffer.text(), "fn a() {\n\n\n \n}");
-
- // indent a line that continues a field expression
- buffer.set_text("fn a() {\n \n}", cx);
- let ix = buffer.len() - 2;
- buffer.edit([(ix..ix, "b\n.c")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(buffer.text(), "fn a() {\n b\n .c\n}");
-
- // indent further lines that continue the field expression, even after empty lines
- let ix = buffer.len() - 2;
- buffer.edit([(ix..ix, "\n\n.d")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(buffer.text(), "fn a() {\n b\n .c\n \n .d\n}");
-
- // dedent the line after the field expression
- let ix = buffer.len() - 2;
- buffer.edit([(ix..ix, ";\ne")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(
- buffer.text(),
- "fn a() {\n b\n .c\n \n .d;\n e\n}"
- );
-
- // indent inside a struct within a call
- buffer.set_text("const a: B = c(D {});", cx);
- let ix = buffer.len() - 3;
- buffer.edit([(ix..ix, "\n\n")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(buffer.text(), "const a: B = c(D {\n \n});");
-
- // indent further inside a nested call
- let ix = buffer.len() - 4;
- buffer.edit([(ix..ix, "e: f(\n\n)")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(buffer.text(), "const a: B = c(D {\n e: f(\n \n )\n});");
-
- // keep that indent after an empty line
- let ix = buffer.len() - 8;
- buffer.edit([(ix..ix, "\n")], Some(AutoindentMode::EachLine), cx);
- assert_eq!(
- buffer.text(),
- "const a: B = c(D {\n e: f(\n \n \n )\n});"
- );
-
- buffer
- });
- }
-}
@@ -1,6 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
-("<" @open ">" @close)
-("\"" @open "\"" @close)
-(closure_parameters "|" @open "|" @close)
@@ -1,13 +0,0 @@
-name = "Rust"
-path_suffixes = ["rs"]
-line_comment = "// "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "<", end = ">", close = false, newline = true, not_in = ["string", "comment"] },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
- { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
-]
-collapsed_placeholder = " /* ... */ "
@@ -1,32 +0,0 @@
-(
- [(line_comment) (attribute_item)]* @context
- .
- [
-
- (struct_item
- name: (_) @name)
-
- (enum_item
- name: (_) @name)
-
- (impl_item
- trait: (_)? @name
- "for"? @name
- type: (_) @name)
-
- (trait_item
- name: (_) @name)
-
- (function_item
- name: (_) @name
- body: (block
- "{" @keep
- "}" @keep) @collapse)
-
- (macro_definition
- name: (_) @name)
- ] @item
- )
-
-(attribute_item) @collapse
-(use_declaration) @collapse
@@ -1,116 +0,0 @@
-(type_identifier) @type
-(primitive_type) @type.builtin
-(self) @variable.special
-(field_identifier) @property
-
-(call_expression
- function: [
- (identifier) @function
- (scoped_identifier
- name: (identifier) @function)
- (field_expression
- field: (field_identifier) @function.method)
- ])
-
-(generic_function
- function: [
- (identifier) @function
- (scoped_identifier
- name: (identifier) @function)
- (field_expression
- field: (field_identifier) @function.method)
- ])
-
-(function_item name: (identifier) @function.definition)
-(function_signature_item name: (identifier) @function.definition)
-
-(macro_invocation
- macro: [
- (identifier) @function.special
- (scoped_identifier
- name: (identifier) @function.special)
- ])
-
-(macro_definition
- name: (identifier) @function.special.definition)
-
-; Identifier conventions
-
-; Assume uppercase names are types/enum-constructors
-((identifier) @type
- (#match? @type "^[A-Z]"))
-
-; Assume all-caps names are constants
-((identifier) @constant
- (#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
-
-[
- "("
- ")"
- "{"
- "}"
- "["
- "]"
-] @punctuation.bracket
-
-(_
- .
- "<" @punctuation.bracket
- ">" @punctuation.bracket)
-
-[
- "as"
- "async"
- "await"
- "break"
- "const"
- "continue"
- "default"
- "dyn"
- "else"
- "enum"
- "extern"
- "for"
- "fn"
- "if"
- "in"
- "impl"
- "let"
- "loop"
- "macro_rules!"
- "match"
- "mod"
- "move"
- "pub"
- "ref"
- "return"
- "static"
- "struct"
- "trait"
- "type"
- "use"
- "where"
- "while"
- "union"
- "unsafe"
- (mutable_specifier)
- (super)
-] @keyword
-
-[
- (string_literal)
- (raw_string_literal)
- (char_literal)
-] @string
-
-[
- (integer_literal)
- (float_literal)
-] @number
-
-(boolean_literal) @constant
-
-[
- (line_comment)
- (block_comment)
-] @comment
@@ -1,14 +0,0 @@
-[
- ((where_clause) _ @end)
- (field_expression)
- (call_expression)
- (assignment_expression)
- (let_declaration)
- (let_chain)
- (await_expression)
-] @indent
-
-(_ "[" "]" @end) @indent
-(_ "<" ">" @end) @indent
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,7 +0,0 @@
-(macro_invocation
- (token_tree) @content
- (#set! "language" "rust"))
-
-(macro_rule
- (token_tree) @content
- (#set! "language" "rust"))
@@ -1,63 +0,0 @@
-(struct_item
- (visibility_modifier)? @context
- "struct" @context
- name: (_) @name) @item
-
-(enum_item
- (visibility_modifier)? @context
- "enum" @context
- name: (_) @name) @item
-
-(enum_variant
- (visibility_modifier)? @context
- name: (_) @name) @item
-
-(impl_item
- "impl" @context
- trait: (_)? @name
- "for"? @context
- type: (_) @name) @item
-
-(trait_item
- (visibility_modifier)? @context
- "trait" @context
- name: (_) @name) @item
-
-(function_item
- (visibility_modifier)? @context
- (function_modifiers)? @context
- "fn" @context
- name: (_) @name) @item
-
-(function_signature_item
- (visibility_modifier)? @context
- (function_modifiers)? @context
- "fn" @context
- name: (_) @name) @item
-
-(macro_definition
- . "macro_rules!" @context
- name: (_) @name) @item
-
-(mod_item
- (visibility_modifier)? @context
- "mod" @context
- name: (_) @name) @item
-
-(type_item
- (visibility_modifier)? @context
- "type" @context
- name: (_) @name) @item
-
-(associated_type
- "type" @context
- name: (_) @name) @item
-
-(const_item
- (visibility_modifier)? @context
- "const" @context
- name: (_) @name) @item
-
-(field_declaration
- (visibility_modifier)? @context
- name: (_) @name) @item
@@ -1,8 +0,0 @@
-[
- (string_literal)
- (raw_string_literal)
-] @string
-[
- (line_comment)
- (block_comment)
-] @comment
@@ -1,3 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
@@ -1,9 +0,0 @@
-name = "Scheme"
-path_suffixes = ["scm", "ss"]
-line_comment = "; "
-autoclose_before = "])"
-brackets = [
- { start = "[", end = "]", close = true, newline = false },
- { start = "(", end = ")", close = true, newline = false },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
-]
@@ -1,28 +0,0 @@
-["(" ")" "[" "]" "{" "}"] @punctuation.bracket
-
-(number) @number
-(character) @constant.builtin
-(boolean) @constant.builtin
-
-(symbol) @variable
-(string) @string
-
-(escape_sequence) @escape
-
-[(comment)
- (block_comment)
- (directive)] @comment
-
-((symbol) @operator
- (#match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$"))
-
-(list
- .
- (symbol) @function)
-
-(list
- .
- (symbol) @keyword
- (#match? @keyword
- "^(define-syntax|let\\*|lambda|λ|case|=>|quote-splicing|unquote-splicing|set!|let|letrec|letrec-syntax|let-values|let\\*-values|do|else|define|cond|syntax-rules|unquote|begin|quote|let-syntax|and|if|quasiquote|letrec|delay|or|when|unless|identifier-syntax|assert|library|export|import|rename|only|except|prefix)$"
- ))
@@ -1,3 +0,0 @@
-(_ "[" "]") @indent
-(_ "{" "}") @indent
-(_ "(" ")") @indent
@@ -1,10 +0,0 @@
-(list
- .
- (symbol) @start-symbol @context
- .
- [
- (symbol) @name
- (list . (symbol) @name)
- ]
- (#match? @start-symbol "^define")
-) @item
@@ -1,6 +0,0 @@
-[
- (comment)
- (block_comment)
- (directive)
-] @comment
-(string) @string
@@ -1,133 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use futures::StreamExt;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use node_runtime::NodeRuntime;
-use serde_json::json;
-use smol::fs;
-use std::{
- any::Any,
- ffi::OsString,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::ResultExt;
-
-const SERVER_PATH: &'static str = "node_modules/svelte-language-server/bin/server.js";
-
-fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-pub struct SvelteLspAdapter {
- node: Arc<dyn NodeRuntime>,
-}
-
-impl SvelteLspAdapter {
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- SvelteLspAdapter { node }
- }
-}
-
-#[async_trait]
-impl LspAdapter for SvelteLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("svelte-language-server".into())
- }
-
- fn short_name(&self) -> &'static str {
- "svelte"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Any + Send>> {
- Ok(Box::new(
- self.node
- .npm_package_latest_version("svelte-language-server")
- .await?,
- ) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<String>().unwrap();
- let server_path = container_dir.join(SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(
- &container_dir,
- &[("svelte-language-server", version.as_str())],
- )
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn initialization_options(&self) -> Option<serde_json::Value> {
- Some(json!({
- "provideFormatter": true
- }))
- }
-
- fn prettier_plugins(&self) -> &[&'static str] {
- &["prettier-plugin-svelte"]
- }
-}
-
-async fn get_cached_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last_version_dir = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_dir() {
- last_version_dir = Some(entry.path());
- }
- }
- let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
- let server_path = last_version_dir.join(SERVER_PATH);
- if server_path.exists() {
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- } else {
- Err(anyhow!(
- "missing executable in directory {:?}",
- last_version_dir
- ))
- }
- })()
- .await
- .log_err()
-}
@@ -1,20 +0,0 @@
-name = "Svelte"
-path_suffixes = ["svelte"]
-line_comment = "// "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "<", end = ">", close = false, newline = true, not_in = ["string", "comment"] },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
- { start = "`", end = "`", close = true, newline = false, not_in = ["string"] },
- { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
-]
-scope_opt_in_language_servers = ["tailwindcss-language-server"]
-prettier_parser_name = "svelte"
-
-[overrides.string]
-word_characters = ["-"]
-opt_into_language_servers = ["tailwindcss-language-server"]
@@ -1,9 +0,0 @@
-[
- (style_element)
- (script_element)
- (element)
- (if_statement)
- (else_statement)
- (each_statement)
- (await_statement)
-] @fold
@@ -1,42 +0,0 @@
-; Special identifiers
-;--------------------
-
-; TODO:
-(tag_name) @tag
-(attribute_name) @property
-(erroneous_end_tag_name) @keyword
-(comment) @comment
-
-[
- (attribute_value)
- (quoted_attribute_value)
-] @string
-
-[
- (text)
- (raw_text_expr)
-] @none
-
-[
- (special_block_keyword)
- (then)
- (as)
-] @keyword
-
-[
- "{"
- "}"
-] @punctuation.bracket
-
-"=" @operator
-
-[
- "<"
- ">"
- "</"
- "/>"
- "#"
- ":"
- "/"
- "@"
-] @tag.delimiter
@@ -1,8 +0,0 @@
-[
- (element)
- (if_statement)
- (each_statement)
- (await_statement)
- (script_element)
- (style_element)
-] @indent
@@ -1,28 +0,0 @@
-; injections.scm
-; --------------
-(script_element
- (raw_text) @content
- (#set! "language" "javascript"))
-
- ((script_element
- (start_tag
- (attribute
- (quoted_attribute_value (attribute_value) @_language)))
- (raw_text) @content)
- (#eq? @_language "ts")
- (#set! "language" "typescript"))
-
-((script_element
- (start_tag
- (attribute
- (quoted_attribute_value (attribute_value) @_language)))
- (raw_text) @content)
- (#eq? @_language "typescript")
- (#set! "language" "typescript"))
-
-(style_element
- (raw_text) @content
- (#set! "language" "css"))
-
-((raw_text_expr) @content
- (#set! "language" "javascript"))
@@ -1,7 +0,0 @@
-(comment) @comment
-
-[
- (raw_text)
- (attribute_value)
- (quoted_attribute_value)
-] @string
@@ -1,171 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use collections::HashMap;
-use futures::{
- future::{self, BoxFuture},
- FutureExt, StreamExt,
-};
-use gpui::AppContext;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use node_runtime::NodeRuntime;
-use serde_json::{json, Value};
-use smol::fs;
-use std::{
- any::Any,
- ffi::OsString,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::ResultExt;
-
-const SERVER_PATH: &'static str = "node_modules/.bin/tailwindcss-language-server";
-
-fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-pub struct TailwindLspAdapter {
- node: Arc<dyn NodeRuntime>,
-}
-
-impl TailwindLspAdapter {
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- TailwindLspAdapter { node }
- }
-}
-
-#[async_trait]
-impl LspAdapter for TailwindLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("tailwindcss-language-server".into())
- }
-
- fn short_name(&self) -> &'static str {
- "tailwind"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Any + Send>> {
- Ok(Box::new(
- self.node
- .npm_package_latest_version("@tailwindcss/language-server")
- .await?,
- ) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<String>().unwrap();
- let server_path = container_dir.join(SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(
- &container_dir,
- &[("@tailwindcss/language-server", version.as_str())],
- )
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn initialization_options(&self) -> Option<serde_json::Value> {
- Some(json!({
- "provideFormatter": true,
- "userLanguages": {
- "html": "html",
- "css": "css",
- "javascript": "javascript",
- "typescriptreact": "typescriptreact",
- },
- }))
- }
-
- fn workspace_configuration(
- &self,
- _workspace_root: &Path,
- _: &mut AppContext,
- ) -> BoxFuture<'static, Value> {
- future::ready(json!({
- "tailwindCSS": {
- "emmetCompletions": true,
- }
- }))
- .boxed()
- }
-
- async fn language_ids(&self) -> HashMap<String, String> {
- HashMap::from_iter([
- ("HTML".to_string(), "html".to_string()),
- ("CSS".to_string(), "css".to_string()),
- ("JavaScript".to_string(), "javascript".to_string()),
- ("TSX".to_string(), "typescriptreact".to_string()),
- ("Svelte".to_string(), "svelte".to_string()),
- ("Elixir".to_string(), "phoenix-heex".to_string()),
- ("HEEX".to_string(), "phoenix-heex".to_string()),
- ("ERB".to_string(), "erb".to_string()),
- ("PHP".to_string(), "php".to_string()),
- ])
- }
-
- fn prettier_plugins(&self) -> &[&'static str] {
- &["prettier-plugin-tailwindcss"]
- }
-}
-
-async fn get_cached_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last_version_dir = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_dir() {
- last_version_dir = Some(entry.path());
- }
- }
- let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
- let server_path = last_version_dir.join(SERVER_PATH);
- if server_path.exists() {
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- } else {
- Err(anyhow!(
- "missing executable in directory {:?}",
- last_version_dir
- ))
- }
- })()
- .await
- .log_err()
-}
@@ -1,3 +0,0 @@
-("[" @open "]" @close)
-("{" @open "}" @close)
-("\"" @open "\"" @close)
@@ -1,10 +0,0 @@
-name = "TOML"
-path_suffixes = ["Cargo.lock", "toml"]
-line_comment = "# "
-autoclose_before = ",]}"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
-]
@@ -1,37 +0,0 @@
-; Properties
-;-----------
-
-(bare_key) @property
-(quoted_key) @property
-
-; Literals
-;---------
-
-(boolean) @constant
-(comment) @comment
-(string) @string
-(integer) @number
-(float) @number
-(offset_date_time) @string.special
-(local_date_time) @string.special
-(local_date) @string.special
-(local_time) @string.special
-
-; Punctuation
-;------------
-
-[
- "."
- ","
-] @punctuation.delimiter
-
-"=" @operator
-
-[
- "["
- "]"
- "[["
- "]]"
- "{"
- "}"
-] @punctuation.bracket
@@ -1,15 +0,0 @@
-(table
- .
- "["
- .
- (_) @name) @item
-
-(table_array_element
- .
- "[["
- .
- (_) @name) @item
-
-(pair
- .
- (_) @name) @item
@@ -1,2 +0,0 @@
-(comment) @comment
-(string) @string
@@ -1 +0,0 @@
-../typescript/brackets.scm
@@ -1,25 +0,0 @@
-name = "TSX"
-path_suffixes = ["tsx"]
-line_comment = "// "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "<", end = ">", close = false, newline = true, not_in = ["string", "comment"] },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
- { start = "`", end = "`", close = true, newline = false, not_in = ["string"] },
- { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
-]
-word_characters = ["#", "$"]
-scope_opt_in_language_servers = ["tailwindcss-language-server"]
-prettier_parser_name = "typescript"
-
-[overrides.element]
-line_comment = { remove = true }
-block_comment = ["{/* ", " */}"]
-
-[overrides.string]
-word_characters = ["-"]
-opt_into_language_servers = ["tailwindcss-language-server"]
@@ -1,85 +0,0 @@
-(
- (comment)* @context
- .
- [
- (export_statement
- (function_declaration
- "async"? @name
- "function" @name
- name: (_) @name))
- (function_declaration
- "async"? @name
- "function" @name
- name: (_) @name)
- ] @item
- )
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (class_declaration
- "class" @name
- name: (_) @name))
- (class_declaration
- "class" @name
- name: (_) @name)
- ] @item
- )
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (interface_declaration
- "interface" @name
- name: (_) @name))
- (interface_declaration
- "interface" @name
- name: (_) @name)
- ] @item
- )
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (enum_declaration
- "enum" @name
- name: (_) @name))
- (enum_declaration
- "enum" @name
- name: (_) @name)
- ] @item
- )
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (type_alias_declaration
- "type" @name
- name: (_) @name))
- (type_alias_declaration
- "type" @name
- name: (_) @name)
- ] @item
- )
-
-(
- (comment)* @context
- .
- (method_definition
- [
- "get"
- "set"
- "async"
- "*"
- "static"
- ]* @name
- name: (_) @name) @item
- )
@@ -1 +0,0 @@
-../typescript/highlights.scm
@@ -1 +0,0 @@
-../typescript/indents.scm
@@ -1 +0,0 @@
-../typescript/outline.scm
@@ -1,18 +0,0 @@
-(comment) @comment
-
-[
- (string)
- (template_string)
-] @string
-
-[
- (jsx_element)
- (jsx_fragment)
-] @element
-
-[
- (jsx_opening_element)
- (jsx_closing_element)
- (jsx_self_closing_element)
- (jsx_expression)
-] @default
@@ -1,400 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_compression::futures::bufread::GzipDecoder;
-use async_tar::Archive;
-use async_trait::async_trait;
-use collections::HashMap;
-use futures::{future::BoxFuture, FutureExt};
-use gpui::AppContext;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::{CodeActionKind, LanguageServerBinary};
-use node_runtime::NodeRuntime;
-use serde_json::{json, Value};
-use smol::{fs, io::BufReader, stream::StreamExt};
-use std::{
- any::Any,
- ffi::OsString,
- future,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::{fs::remove_matching, github::latest_github_release};
-use util::{github::GitHubLspBinaryVersion, ResultExt};
-
-fn typescript_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-fn eslint_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-pub struct TypeScriptLspAdapter {
- node: Arc<dyn NodeRuntime>,
-}
-
-impl TypeScriptLspAdapter {
- const OLD_SERVER_PATH: &'static str = "node_modules/typescript-language-server/lib/cli.js";
- const NEW_SERVER_PATH: &'static str = "node_modules/typescript-language-server/lib/cli.mjs";
-
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- TypeScriptLspAdapter { node }
- }
-}
-
-struct TypeScriptVersions {
- typescript_version: String,
- server_version: String,
-}
-
-#[async_trait]
-impl LspAdapter for TypeScriptLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("typescript-language-server".into())
- }
-
- fn short_name(&self) -> &'static str {
- "tsserver"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- Ok(Box::new(TypeScriptVersions {
- typescript_version: self.node.npm_package_latest_version("typescript").await?,
- server_version: self
- .node
- .npm_package_latest_version("typescript-language-server")
- .await?,
- }) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<TypeScriptVersions>().unwrap();
- let server_path = container_dir.join(Self::NEW_SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(
- &container_dir,
- &[
- ("typescript", version.typescript_version.as_str()),
- (
- "typescript-language-server",
- version.server_version.as_str(),
- ),
- ],
- )
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: typescript_server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_ts_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_ts_server_binary(container_dir, &*self.node).await
- }
-
- fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
- Some(vec![
- CodeActionKind::QUICKFIX,
- CodeActionKind::REFACTOR,
- CodeActionKind::REFACTOR_EXTRACT,
- CodeActionKind::SOURCE,
- ])
- }
-
- async fn label_for_completion(
- &self,
- item: &lsp::CompletionItem,
- language: &Arc<language::Language>,
- ) -> Option<language::CodeLabel> {
- use lsp::CompletionItemKind as Kind;
- let len = item.label.len();
- let grammar = language.grammar()?;
- let highlight_id = match item.kind? {
- Kind::CLASS | Kind::INTERFACE => grammar.highlight_id_for_name("type"),
- Kind::CONSTRUCTOR => grammar.highlight_id_for_name("type"),
- Kind::CONSTANT => grammar.highlight_id_for_name("constant"),
- Kind::FUNCTION | Kind::METHOD => grammar.highlight_id_for_name("function"),
- Kind::PROPERTY | Kind::FIELD => grammar.highlight_id_for_name("property"),
- _ => None,
- }?;
-
- let text = match &item.detail {
- Some(detail) => format!("{} {}", item.label, detail),
- None => item.label.clone(),
- };
-
- Some(language::CodeLabel {
- text,
- runs: vec![(0..len, highlight_id)],
- filter_range: 0..len,
- })
- }
-
- async fn initialization_options(&self) -> Option<serde_json::Value> {
- Some(json!({
- "provideFormatter": true,
- "tsserver": {
- "path": "node_modules/typescript/lib",
- },
- }))
- }
-
- async fn language_ids(&self) -> HashMap<String, String> {
- HashMap::from_iter([
- ("TypeScript".into(), "typescript".into()),
- ("JavaScript".into(), "javascript".into()),
- ("TSX".into(), "typescriptreact".into()),
- ])
- }
-}
-
-async fn get_cached_ts_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- (|| async move {
- let old_server_path = container_dir.join(TypeScriptLspAdapter::OLD_SERVER_PATH);
- let new_server_path = container_dir.join(TypeScriptLspAdapter::NEW_SERVER_PATH);
- if new_server_path.exists() {
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: typescript_server_binary_arguments(&new_server_path),
- })
- } else if old_server_path.exists() {
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: typescript_server_binary_arguments(&old_server_path),
- })
- } else {
- Err(anyhow!(
- "missing executable in directory {:?}",
- container_dir
- ))
- }
- })()
- .await
- .log_err()
-}
-
-pub struct EsLintLspAdapter {
- node: Arc<dyn NodeRuntime>,
-}
-
-impl EsLintLspAdapter {
- const SERVER_PATH: &'static str = "vscode-eslint/server/out/eslintServer.js";
-
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- EsLintLspAdapter { node }
- }
-}
-
-#[async_trait]
-impl LspAdapter for EsLintLspAdapter {
- fn workspace_configuration(
- &self,
- workspace_root: &Path,
- _: &mut AppContext,
- ) -> BoxFuture<'static, Value> {
- future::ready(json!({
- "": {
- "validate": "on",
- "rulesCustomizations": [],
- "run": "onType",
- "nodePath": null,
- "workingDirectory": {"mode": "auto"},
- "workspaceFolder": {
- "uri": workspace_root,
- "name": workspace_root.file_name()
- .unwrap_or_else(|| workspace_root.as_os_str()),
- },
- }
- }))
- .boxed()
- }
-
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("eslint".into())
- }
-
- fn short_name(&self) -> &'static str {
- "eslint"
- }
-
- async fn fetch_latest_server_version(
- &self,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- // At the time of writing the latest vscode-eslint release was released in 2020 and requires
- // special custom LSP protocol extensions be handled to fully initialize. Download the latest
- // prerelease instead to sidestep this issue
- let release =
- latest_github_release("microsoft/vscode-eslint", true, delegate.http_client()).await?;
- Ok(Box::new(GitHubLspBinaryVersion {
- name: release.name,
- url: release.tarball_url,
- }))
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- delegate: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
- let destination_path = container_dir.join(format!("vscode-eslint-{}", version.name));
- let server_path = destination_path.join(Self::SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- remove_matching(&container_dir, |entry| entry != destination_path).await;
-
- let mut response = delegate
- .http_client()
- .get(&version.url, Default::default(), true)
- .await
- .map_err(|err| anyhow!("error downloading release: {}", err))?;
- let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
- let archive = Archive::new(decompressed_bytes);
- archive.unpack(&destination_path).await?;
-
- let mut dir = fs::read_dir(&destination_path).await?;
- let first = dir.next().await.ok_or(anyhow!("missing first file"))??;
- let repo_root = destination_path.join("vscode-eslint");
- fs::rename(first.path(), &repo_root).await?;
-
- self.node
- .run_npm_subcommand(Some(&repo_root), "install", &[])
- .await?;
-
- self.node
- .run_npm_subcommand(Some(&repo_root), "run-script", &["compile"])
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: eslint_server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_eslint_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_eslint_server_binary(container_dir, &*self.node).await
- }
-
- async fn label_for_completion(
- &self,
- _item: &lsp::CompletionItem,
- _language: &Arc<language::Language>,
- ) -> Option<language::CodeLabel> {
- None
- }
-
- async fn initialization_options(&self) -> Option<serde_json::Value> {
- None
- }
-}
-
-async fn get_cached_eslint_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- (|| async move {
- // This is unfortunate but we don't know what the version is to build a path directly
- let mut dir = fs::read_dir(&container_dir).await?;
- let first = dir.next().await.ok_or(anyhow!("missing first file"))??;
- if !first.file_type().await?.is_dir() {
- return Err(anyhow!("First entry is not a directory"));
- }
- let server_path = first.path().join(EsLintLspAdapter::SERVER_PATH);
-
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: eslint_server_binary_arguments(&server_path),
- })
- })()
- .await
- .log_err()
-}
-
-#[cfg(test)]
-mod tests {
- use gpui::{Context, TestAppContext};
- use unindent::Unindent;
-
- #[gpui::test]
- async fn test_outline(cx: &mut TestAppContext) {
- let language = crate::languages::language(
- "typescript",
- tree_sitter_typescript::language_typescript(),
- None,
- )
- .await;
-
- let text = r#"
- function a() {
- // local variables are omitted
- let a1 = 1;
- // all functions are included
- async function a2() {}
- }
- // top-level variables are included
- let b: C
- function getB() {}
- // exported variables are included
- export const d = e;
- "#
- .unindent();
-
- let buffer = cx.new_model(|cx| {
- language::Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx)
- });
- let outline = buffer.update(cx, |buffer, _| buffer.snapshot().outline(None).unwrap());
- assert_eq!(
- outline
- .items
- .iter()
- .map(|item| (item.text.as_str(), item.depth))
- .collect::<Vec<_>>(),
- &[
- ("function a()", 0),
- ("async function a2()", 1),
- ("let b", 0),
- ("function getB()", 0),
- ("const d", 0),
- ]
- );
- }
-}
@@ -1,5 +0,0 @@
-("(" @open ")" @close)
-("[" @open "]" @close)
-("{" @open "}" @close)
-("<" @open ">" @close)
-("\"" @open "\"" @close)
@@ -1,16 +0,0 @@
-name = "TypeScript"
-path_suffixes = ["ts", "cts", "d.cts", "d.mts", "mts"]
-line_comment = "// "
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "<", end = ">", close = false, newline = true, not_in = ["string", "comment"] },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
- { start = "`", end = "`", close = true, newline = false, not_in = ["string"] },
- { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
-]
-word_characters = ["#", "$"]
-prettier_parser_name = "typescript"
@@ -1,85 +0,0 @@
-(
- (comment)* @context
- .
- [
- (export_statement
- (function_declaration
- "async"? @name
- "function" @name
- name: (_) @name))
- (function_declaration
- "async"? @name
- "function" @name
- name: (_) @name)
- ] @item
-)
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (class_declaration
- "class" @name
- name: (_) @name))
- (class_declaration
- "class" @name
- name: (_) @name)
- ] @item
-)
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (interface_declaration
- "interface" @name
- name: (_) @name))
- (interface_declaration
- "interface" @name
- name: (_) @name)
- ] @item
-)
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (enum_declaration
- "enum" @name
- name: (_) @name))
- (enum_declaration
- "enum" @name
- name: (_) @name)
- ] @item
-)
-
-(
- (comment)* @context
- .
- [
- (export_statement
- (type_alias_declaration
- "type" @name
- name: (_) @name))
- (type_alias_declaration
- "type" @name
- name: (_) @name)
- ] @item
-)
-
-(
- (comment)* @context
- .
- (method_definition
- [
- "get"
- "set"
- "async"
- "*"
- "static"
- ]* @name
- name: (_) @name) @item
-)
@@ -1,221 +0,0 @@
-; Variables
-
-(identifier) @variable
-
-; Properties
-
-(property_identifier) @property
-
-; Function and method calls
-
-(call_expression
- function: (identifier) @function)
-
-(call_expression
- function: (member_expression
- property: (property_identifier) @function.method))
-
-; Function and method definitions
-
-(function
- name: (identifier) @function)
-(function_declaration
- name: (identifier) @function)
-(method_definition
- name: (property_identifier) @function.method)
-
-(pair
- key: (property_identifier) @function.method
- value: [(function) (arrow_function)])
-
-(assignment_expression
- left: (member_expression
- property: (property_identifier) @function.method)
- right: [(function) (arrow_function)])
-
-(variable_declarator
- name: (identifier) @function
- value: [(function) (arrow_function)])
-
-(assignment_expression
- left: (identifier) @function
- right: [(function) (arrow_function)])
-
-; Special identifiers
-
-((identifier) @constructor
- (#match? @constructor "^[A-Z]"))
-
-((identifier) @type
- (#match? @type "^[A-Z]"))
-(type_identifier) @type
-(predefined_type) @type.builtin
-
-([
- (identifier)
- (shorthand_property_identifier)
- (shorthand_property_identifier_pattern)
- ] @constant
- (#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
-
-; Literals
-
-(this) @variable.special
-(super) @variable.special
-
-[
- (null)
- (undefined)
-] @constant.builtin
-
-[
- (true)
- (false)
-] @boolean
-
-(comment) @comment
-
-[
- (string)
- (template_string)
-] @string
-
-(regex) @string.regex
-(number) @number
-
-; Tokens
-
-[
- ";"
- "?."
- "."
- ","
- ":"
-] @punctuation.delimiter
-
-[
- "-"
- "--"
- "-="
- "+"
- "++"
- "+="
- "*"
- "*="
- "**"
- "**="
- "/"
- "/="
- "%"
- "%="
- "<"
- "<="
- "<<"
- "<<="
- "="
- "=="
- "==="
- "!"
- "!="
- "!=="
- "=>"
- ">"
- ">="
- ">>"
- ">>="
- ">>>"
- ">>>="
- "~"
- "^"
- "&"
- "|"
- "^="
- "&="
- "|="
- "&&"
- "||"
- "??"
- "&&="
- "||="
- "??="
-] @operator
-
-[
- "("
- ")"
- "["
- "]"
- "{"
- "}"
-] @punctuation.bracket
-
-[
- "as"
- "async"
- "await"
- "break"
- "case"
- "catch"
- "class"
- "const"
- "continue"
- "debugger"
- "default"
- "delete"
- "do"
- "else"
- "export"
- "extends"
- "finally"
- "for"
- "from"
- "function"
- "get"
- "if"
- "import"
- "in"
- "instanceof"
- "let"
- "new"
- "of"
- "return"
- "satisfies"
- "set"
- "static"
- "switch"
- "target"
- "throw"
- "try"
- "typeof"
- "var"
- "void"
- "while"
- "with"
- "yield"
-] @keyword
-
-(template_substitution
- "${" @punctuation.special
- "}" @punctuation.special) @embedded
-
-(type_arguments
- "<" @punctuation.bracket
- ">" @punctuation.bracket)
-
-; Keywords
-
-[ "abstract"
- "declare"
- "enum"
- "export"
- "implements"
- "interface"
- "keyof"
- "namespace"
- "private"
- "protected"
- "public"
- "type"
- "readonly"
- "override"
-] @keyword
@@ -1,15 +0,0 @@
-[
- (call_expression)
- (assignment_expression)
- (member_expression)
- (lexical_declaration)
- (variable_declaration)
- (assignment_expression)
- (if_statement)
- (for_statement)
-] @indent
-
-(_ "[" "]" @end) @indent
-(_ "<" ">" @end) @indent
-(_ "{" "}" @end) @indent
-(_ "(" ")" @end) @indent
@@ -1,65 +0,0 @@
-(internal_module
- "namespace" @context
- name: (_) @name) @item
-
-(enum_declaration
- "enum" @context
- name: (_) @name) @item
-
-(type_alias_declaration
- "type" @context
- name: (_) @name) @item
-
-(function_declaration
- "async"? @context
- "function" @context
- name: (_) @name
- parameters: (formal_parameters
- "(" @context
- ")" @context)) @item
-
-(interface_declaration
- "interface" @context
- name: (_) @name) @item
-
-(export_statement
- (lexical_declaration
- ["let" "const"] @context
- (variable_declarator
- name: (_) @name) @item))
-
-(program
- (lexical_declaration
- ["let" "const"] @context
- (variable_declarator
- name: (_) @name) @item))
-
-(class_declaration
- "class" @context
- name: (_) @name) @item
-
-(method_definition
- [
- "get"
- "set"
- "async"
- "*"
- "readonly"
- "static"
- (override_modifier)
- (accessibility_modifier)
- ]* @context
- name: (_) @name
- parameters: (formal_parameters
- "(" @context
- ")" @context)) @item
-
-(public_field_definition
- [
- "declare"
- "readonly"
- "abstract"
- "static"
- (accessibility_modifier)
- ]* @context
- name: (_) @name) @item
@@ -1,2 +0,0 @@
-(comment) @comment
-(string) @string
@@ -1,55 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
-use lsp::LanguageServerBinary;
-use std::{any::Any, path::PathBuf};
-
-pub struct UiuaLanguageServer;
-
-#[async_trait]
-impl LspAdapter for UiuaLanguageServer {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("uiua".into())
- }
-
- fn short_name(&self) -> &'static str {
- "uiua"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Any + Send>> {
- Ok(Box::new(()))
- }
-
- async fn fetch_server_binary(
- &self,
- _version: Box<dyn 'static + Send + Any>,
- _container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- Err(anyhow!(
- "uiua must be installed and available in your $PATH"
- ))
- }
-
- async fn cached_server_binary(
- &self,
- _: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- Some(LanguageServerBinary {
- path: "uiua".into(),
- arguments: vec!["lsp".into()],
- })
- }
-
- fn can_be_reinstalled(&self) -> bool {
- false
- }
-
- async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
- None
- }
-}
@@ -1,10 +0,0 @@
-name = "Uiua"
-path_suffixes = ["ua"]
-line_comment = "# "
-autoclose_before = ")]}\""
-brackets = [
- { start = "{", end = "}", close = true, newline = false},
- { start = "[", end = "]", close = true, newline = false },
- { start = "(", end = ")", close = true, newline = false },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
-]
@@ -1,50 +0,0 @@
-[
- (openParen)
- (closeParen)
- (openCurly)
- (closeCurly)
- (openBracket)
- (closeBracket)
-] @punctuation.bracket
-
-[
- (branchSeparator)
- (underscore)
-] @constructor
-; ] @punctuation.delimiter
-
-[ (character) ] @constant.character
-[ (comment) ] @comment
-[ (constant) ] @constant.numeric
-[ (identifier) ] @variable
-[ (leftArrow) ] @keyword
-[ (function) ] @function
-[ (modifier1) ] @operator
-[ (modifier2) ] @operator
-[ (number) ] @constant.numeric
-[ (placeHolder) ] @special
-[ (otherConstant) ] @string.special
-[ (signature) ] @type
-[ (system) ] @function.builtin
-[ (tripleMinus) ] @module
-
-; planet
-[
- "id"
- "identity"
- "∘"
- "dip"
- "⊙"
- "gap"
- "⋅"
-] @tag
-
-[
- (string)
- (multiLineString)
-] @string
-
-; [
-; (deprecated)
-; (identifierDeprecated)
-; ] @warning
@@ -1,3 +0,0 @@
-[
- (array)
-] @indent
@@ -1,220 +0,0 @@
-use anyhow::{anyhow, ensure, Result};
-use async_trait::async_trait;
-use futures::StreamExt;
-pub use language::*;
-use lsp::{CodeActionKind, LanguageServerBinary};
-use node_runtime::NodeRuntime;
-use parking_lot::Mutex;
-use serde_json::Value;
-use smol::fs::{self};
-use std::{
- any::Any,
- ffi::OsString,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::ResultExt;
-
-pub struct VueLspVersion {
- vue_version: String,
- ts_version: String,
-}
-
-pub struct VueLspAdapter {
- node: Arc<dyn NodeRuntime>,
- typescript_install_path: Mutex<Option<PathBuf>>,
-}
-
-impl VueLspAdapter {
- const SERVER_PATH: &'static str =
- "node_modules/@vue/language-server/bin/vue-language-server.js";
- // TODO: this can't be hardcoded, yet we have to figure out how to pass it in initialization_options.
- const TYPESCRIPT_PATH: &'static str = "node_modules/typescript/lib";
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- let typescript_install_path = Mutex::new(None);
- Self {
- node,
- typescript_install_path,
- }
- }
-}
-#[async_trait]
-impl super::LspAdapter for VueLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("vue-language-server".into())
- }
-
- fn short_name(&self) -> &'static str {
- "vue-language-server"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Send + Any>> {
- Ok(Box::new(VueLspVersion {
- vue_version: self
- .node
- .npm_package_latest_version("@vue/language-server")
- .await?,
- ts_version: self.node.npm_package_latest_version("typescript").await?,
- }) as Box<_>)
- }
- async fn initialization_options(&self) -> Option<Value> {
- let typescript_sdk_path = self.typescript_install_path.lock();
- let typescript_sdk_path = typescript_sdk_path
- .as_ref()
- .expect("initialization_options called without a container_dir for typescript");
-
- Some(serde_json::json!({
- "typescript": {
- "tsdk": typescript_sdk_path
- }
- }))
- }
- fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
- // REFACTOR is explicitly disabled, as vue-lsp does not adhere to LSP protocol for code actions with these - it
- // sends back a CodeAction with neither `command` nor `edits` fields set, which is against the spec.
- Some(vec![
- CodeActionKind::EMPTY,
- CodeActionKind::QUICKFIX,
- CodeActionKind::REFACTOR_REWRITE,
- ])
- }
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<VueLspVersion>().unwrap();
- let server_path = container_dir.join(Self::SERVER_PATH);
- let ts_path = container_dir.join(Self::TYPESCRIPT_PATH);
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(
- &container_dir,
- &[("@vue/language-server", version.vue_version.as_str())],
- )
- .await?;
- }
- ensure!(
- fs::metadata(&server_path).await.is_ok(),
- "@vue/language-server package installation failed"
- );
- if fs::metadata(&ts_path).await.is_err() {
- self.node
- .npm_install_packages(
- &container_dir,
- &[("typescript", version.ts_version.as_str())],
- )
- .await?;
- }
-
- ensure!(
- fs::metadata(&ts_path).await.is_ok(),
- "typescript for Vue package installation failed"
- );
- *self.typescript_install_path.lock() = Some(ts_path);
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: vue_server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- let (server, ts_path) = get_cached_server_binary(container_dir, self.node.clone()).await?;
- *self.typescript_install_path.lock() = Some(ts_path);
- Some(server)
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- let (server, ts_path) = get_cached_server_binary(container_dir, self.node.clone())
- .await
- .map(|(mut binary, ts_path)| {
- binary.arguments = vec!["--help".into()];
- (binary, ts_path)
- })?;
- *self.typescript_install_path.lock() = Some(ts_path);
- Some(server)
- }
-
- async fn label_for_completion(
- &self,
- item: &lsp::CompletionItem,
- language: &Arc<language::Language>,
- ) -> Option<language::CodeLabel> {
- use lsp::CompletionItemKind as Kind;
- let len = item.label.len();
- let grammar = language.grammar()?;
- let highlight_id = match item.kind? {
- Kind::CLASS | Kind::INTERFACE => grammar.highlight_id_for_name("type"),
- Kind::CONSTRUCTOR => grammar.highlight_id_for_name("type"),
- Kind::CONSTANT => grammar.highlight_id_for_name("constant"),
- Kind::FUNCTION | Kind::METHOD => grammar.highlight_id_for_name("function"),
- Kind::PROPERTY | Kind::FIELD => grammar.highlight_id_for_name("tag"),
- Kind::VARIABLE => grammar.highlight_id_for_name("type"),
- Kind::KEYWORD => grammar.highlight_id_for_name("keyword"),
- Kind::VALUE => grammar.highlight_id_for_name("tag"),
- _ => None,
- }?;
-
- let text = match &item.detail {
- Some(detail) => format!("{} {}", item.label, detail),
- None => item.label.clone(),
- };
-
- Some(language::CodeLabel {
- text,
- runs: vec![(0..len, highlight_id)],
- filter_range: 0..len,
- })
- }
-}
-
-fn vue_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-type TypescriptPath = PathBuf;
-async fn get_cached_server_binary(
- container_dir: PathBuf,
- node: Arc<dyn NodeRuntime>,
-) -> Option<(LanguageServerBinary, TypescriptPath)> {
- (|| async move {
- let mut last_version_dir = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_dir() {
- last_version_dir = Some(entry.path());
- }
- }
- let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
- let server_path = last_version_dir.join(VueLspAdapter::SERVER_PATH);
- let typescript_path = last_version_dir.join(VueLspAdapter::TYPESCRIPT_PATH);
- if server_path.exists() && typescript_path.exists() {
- Ok((
- LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: vue_server_binary_arguments(&server_path),
- },
- typescript_path,
- ))
- } else {
- Err(anyhow!(
- "missing executable in directory {:?}",
- last_version_dir
- ))
- }
- })()
- .await
- .log_err()
-}
@@ -1,2 +0,0 @@
-("<" @open ">" @close)
-("\"" @open "\"" @close)
@@ -1,14 +0,0 @@
-name = "Vue.js"
-path_suffixes = ["vue"]
-block_comment = ["<!-- ", " -->"]
-autoclose_before = ";:.,=}])>"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "(", end = ")", close = true, newline = true },
- { start = "<", end = ">", close = true, newline = true, not_in = ["string", "comment"] },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
- { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
- { start = "`", end = "`", close = true, newline = false, not_in = ["string"] },
-]
-word_characters = ["-"]
@@ -1,15 +0,0 @@
-(attribute) @property
-(directive_attribute) @property
-(quoted_attribute_value) @string
-(interpolation) @punctuation.special
-(raw_text) @embedded
-
-((tag_name) @type
- (#match? @type "^[A-Z]"))
-
-((directive_name) @keyword
- (#match? @keyword "^v-"))
-
-(start_tag) @tag
-(end_tag) @tag
-(self_closing_tag) @tag
@@ -1,7 +0,0 @@
-(script_element
- (raw_text) @content
- (#set! "language" "javascript"))
-
-(style_element
- (raw_text) @content
- (#set! "language" "css"))
@@ -1,146 +0,0 @@
-use anyhow::{anyhow, Result};
-use async_trait::async_trait;
-use futures::{future::BoxFuture, FutureExt, StreamExt};
-use gpui::AppContext;
-use language::{
- language_settings::all_language_settings, LanguageServerName, LspAdapter, LspAdapterDelegate,
-};
-use lsp::LanguageServerBinary;
-use node_runtime::NodeRuntime;
-use serde_json::Value;
-use smol::fs;
-use std::{
- any::Any,
- ffi::OsString,
- future,
- path::{Path, PathBuf},
- sync::Arc,
-};
-use util::ResultExt;
-
-const SERVER_PATH: &'static str = "node_modules/yaml-language-server/bin/yaml-language-server";
-
-fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
- vec![server_path.into(), "--stdio".into()]
-}
-
-pub struct YamlLspAdapter {
- node: Arc<dyn NodeRuntime>,
-}
-
-impl YamlLspAdapter {
- pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
- YamlLspAdapter { node }
- }
-}
-
-#[async_trait]
-impl LspAdapter for YamlLspAdapter {
- async fn name(&self) -> LanguageServerName {
- LanguageServerName("yaml-language-server".into())
- }
-
- fn short_name(&self) -> &'static str {
- "yaml"
- }
-
- async fn fetch_latest_server_version(
- &self,
- _: &dyn LspAdapterDelegate,
- ) -> Result<Box<dyn 'static + Any + Send>> {
- Ok(Box::new(
- self.node
- .npm_package_latest_version("yaml-language-server")
- .await?,
- ) as Box<_>)
- }
-
- async fn fetch_server_binary(
- &self,
- version: Box<dyn 'static + Send + Any>,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Result<LanguageServerBinary> {
- let version = version.downcast::<String>().unwrap();
- let server_path = container_dir.join(SERVER_PATH);
-
- if fs::metadata(&server_path).await.is_err() {
- self.node
- .npm_install_packages(
- &container_dir,
- &[("yaml-language-server", version.as_str())],
- )
- .await?;
- }
-
- Ok(LanguageServerBinary {
- path: self.node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- }
-
- async fn cached_server_binary(
- &self,
- container_dir: PathBuf,
- _: &dyn LspAdapterDelegate,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
-
- async fn installation_test_binary(
- &self,
- container_dir: PathBuf,
- ) -> Option<LanguageServerBinary> {
- get_cached_server_binary(container_dir, &*self.node).await
- }
- fn workspace_configuration(
- &self,
- _workspace_root: &Path,
- cx: &mut AppContext,
- ) -> BoxFuture<'static, Value> {
- let tab_size = all_language_settings(None, cx)
- .language(Some("YAML"))
- .tab_size;
-
- future::ready(serde_json::json!({
- "yaml": {
- "keyOrdering": false
- },
- "[yaml]": {
- "editor.tabSize": tab_size,
- }
- }))
- .boxed()
- }
-}
-
-async fn get_cached_server_binary(
- container_dir: PathBuf,
- node: &dyn NodeRuntime,
-) -> Option<LanguageServerBinary> {
- (|| async move {
- let mut last_version_dir = None;
- let mut entries = fs::read_dir(&container_dir).await?;
- while let Some(entry) = entries.next().await {
- let entry = entry?;
- if entry.file_type().await?.is_dir() {
- last_version_dir = Some(entry.path());
- }
- }
- let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
- let server_path = last_version_dir.join(SERVER_PATH);
- if server_path.exists() {
- Ok(LanguageServerBinary {
- path: node.binary_path().await?,
- arguments: server_binary_arguments(&server_path),
- })
- } else {
- Err(anyhow!(
- "missing executable in directory {:?}",
- last_version_dir
- ))
- }
- })()
- .await
- .log_err()
-}
@@ -1,3 +0,0 @@
-("[" @open "]" @close)
-("{" @open "}" @close)
-("\"" @open "\"" @close)
@@ -1,12 +0,0 @@
-name = "YAML"
-path_suffixes = ["yml", "yaml"]
-line_comment = "# "
-autoclose_before = ",]}"
-brackets = [
- { start = "{", end = "}", close = true, newline = true },
- { start = "[", end = "]", close = true, newline = true },
- { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
-]
-
-increase_indent_pattern = ":\\s*[|>]?\\s*$"
-prettier_parser_name = "yaml"
@@ -1,49 +0,0 @@
-(boolean_scalar) @boolean
-(null_scalar) @constant.builtin
-
-[
- (double_quote_scalar)
- (single_quote_scalar)
- (block_scalar)
- (string_scalar)
-] @string
-
-(escape_sequence) @string.escape
-
-[
- (integer_scalar)
- (float_scalar)
-] @number
-
-(comment) @comment
-
-[
- (anchor_name)
- (alias_name)
- (tag)
-] @type
-
-key: (flow_node (plain_scalar (string_scalar) @property))
-
-[
- ","
- "-"
- ":"
- ">"
- "?"
- "|"
-] @punctuation.delimiter
-
-[
- "["
- "]"
- "{"
- "}"
-] @punctuation.bracket
-
-[
- "*"
- "&"
- "---"
- "..."
-] @punctuation.special
@@ -1 +0,0 @@
-(block_mapping_pair key: (flow_node (plain_scalar (string_scalar) @name))) @item
@@ -1,799 +0,0 @@
-// Allow binary to be called Zed for a nice application menu when running executable directly
-#![allow(non_snake_case)]
-
-use anyhow::{anyhow, Context as _, Result};
-use backtrace::Backtrace;
-use chrono::Utc;
-use cli::FORCE_CLI_MODE_ENV_VAR_NAME;
-use client::{Client, UserStore};
-use collab_ui::channel_view::ChannelView;
-use db::kvp::KEY_VALUE_STORE;
-use editor::Editor;
-use fs::RealFs;
-use futures::StreamExt;
-use gpui::{App, AppContext, AsyncAppContext, Context, SemanticVersion, Task};
-use isahc::{prelude::Configurable, Request};
-use language::LanguageRegistry;
-use log::LevelFilter;
-
-use node_runtime::RealNodeRuntime;
-use parking_lot::Mutex;
-use serde::{Deserialize, Serialize};
-use settings::{
- default_settings, handle_settings_file_changes, watch_config_file, Settings, SettingsStore,
-};
-use simplelog::ConfigBuilder;
-use smol::process::Command;
-use std::{
- env,
- ffi::OsStr,
- fs::OpenOptions,
- io::{IsTerminal, Write},
- panic,
- path::{Path, PathBuf},
- sync::{
- atomic::{AtomicU32, Ordering},
- Arc, Weak,
- },
- thread,
-};
-use theme::ActiveTheme;
-use util::{
- async_maybe,
- channel::{parse_zed_link, AppCommitSha, ReleaseChannel, RELEASE_CHANNEL},
- http::{self, HttpClient},
- paths, ResultExt,
-};
-use uuid::Uuid;
-use welcome::{show_welcome_view, FIRST_OPEN};
-use workspace::{AppState, WorkspaceStore};
-use zed2::{
- app_menus, build_window_options, ensure_only_instance, handle_cli_connection,
- handle_keymap_file_changes, initialize_workspace, languages, Assets, IsOnlyInstance,
- OpenListener, OpenRequest,
-};
-
-fn main() {
- menu::init();
- zed_actions::init();
-
- let http = http::client();
- init_paths();
- init_logger();
-
- if ensure_only_instance() != IsOnlyInstance::Yes {
- return;
- }
-
- log::info!("========== starting zed ==========");
- let app = App::production(Arc::new(Assets));
-
- let (installation_id, existing_installation_id_found) = app
- .background_executor()
- .block(installation_id())
- .ok()
- .unzip();
- let session_id = Uuid::new_v4().to_string();
- init_panic_hook(&app, installation_id.clone(), session_id.clone());
-
- let fs = Arc::new(RealFs);
- let user_settings_file_rx = watch_config_file(
- &app.background_executor(),
- fs.clone(),
- paths::SETTINGS.clone(),
- );
- let user_keymap_file_rx = watch_config_file(
- &app.background_executor(),
- fs.clone(),
- paths::KEYMAP.clone(),
- );
-
- let login_shell_env_loaded = if stdout_is_a_pty() {
- Task::ready(())
- } else {
- app.background_executor().spawn(async {
- load_login_shell_environment().await.log_err();
- })
- };
-
- let (listener, mut open_rx) = OpenListener::new();
- let listener = Arc::new(listener);
- let open_listener = listener.clone();
- app.on_open_urls(move |urls, _| open_listener.open_urls(&urls));
- app.on_reopen(move |cx| {
- if cx.has_global::<Weak<AppState>>() {
- if let Some(app_state) = cx.global::<Weak<AppState>>().upgrade() {
- workspace::open_new(&app_state, cx, |workspace, cx| {
- Editor::new_file(workspace, &Default::default(), cx)
- })
- .detach();
- }
- }
- });
-
- app.run(move |cx| {
- cx.set_global(*RELEASE_CHANNEL);
- if let Some(build_sha) = option_env!("ZED_COMMIT_SHA") {
- cx.set_global(AppCommitSha(build_sha.into()))
- }
-
- cx.set_global(listener.clone());
-
- load_embedded_fonts(cx);
-
- let mut store = SettingsStore::default();
- store
- .set_default_settings(default_settings().as_ref(), cx)
- .unwrap();
- cx.set_global(store);
- handle_settings_file_changes(user_settings_file_rx, cx);
- handle_keymap_file_changes(user_keymap_file_rx, cx);
-
- let client = client::Client::new(http.clone(), cx);
- let mut languages = LanguageRegistry::new(login_shell_env_loaded);
- let copilot_language_server_id = languages.next_language_server_id();
- languages.set_executor(cx.background_executor().clone());
- languages.set_language_server_download_dir(paths::LANGUAGES_DIR.clone());
- let languages = Arc::new(languages);
- let node_runtime = RealNodeRuntime::new(http.clone());
-
- language::init(cx);
- languages::init(languages.clone(), node_runtime.clone(), cx);
- let user_store = cx.new_model(|cx| UserStore::new(client.clone(), cx));
- let workspace_store = cx.new_model(|cx| WorkspaceStore::new(client.clone(), cx));
-
- cx.set_global(client.clone());
-
- theme::init(theme::LoadThemes::All, cx);
- project::Project::init(&client, cx);
- client::init(&client, cx);
- command_palette::init(cx);
- language::init(cx);
- editor::init(cx);
- diagnostics::init(cx);
- copilot::init(
- copilot_language_server_id,
- http.clone(),
- node_runtime.clone(),
- cx,
- );
- assistant::init(cx);
- // component_test::init(cx);
-
- cx.spawn(|_| watch_languages(fs.clone(), languages.clone()))
- .detach();
- watch_file_types(fs.clone(), cx);
-
- languages.set_theme(cx.theme().clone());
- cx.observe_global::<SettingsStore>({
- let languages = languages.clone();
- move |cx| languages.set_theme(cx.theme().clone())
- })
- .detach();
-
- client.telemetry().start(installation_id, session_id, cx);
- let telemetry_settings = *client::TelemetrySettings::get_global(cx);
- client.telemetry().report_setting_event(
- telemetry_settings,
- "theme",
- cx.theme().name.to_string(),
- );
- let event_operation = match existing_installation_id_found {
- Some(false) => "first open",
- _ => "open",
- };
- client
- .telemetry()
- .report_app_event(telemetry_settings, event_operation, true);
-
- let app_state = Arc::new(AppState {
- languages: languages.clone(),
- client: client.clone(),
- user_store: user_store.clone(),
- fs: fs.clone(),
- build_window_options,
- workspace_store,
- node_runtime,
- });
- cx.set_global(Arc::downgrade(&app_state));
-
- audio::init(Assets, cx);
- auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx);
-
- workspace::init(app_state.clone(), cx);
- recent_projects::init(cx);
-
- go_to_line::init(cx);
- file_finder::init(cx);
- outline::init(cx);
- project_symbols::init(cx);
- project_panel::init(Assets, cx);
- channel::init(&client, user_store.clone(), cx);
- search::init(cx);
- semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx);
- vim::init(cx);
- terminal_view::init(cx);
-
- journal::init(app_state.clone(), cx);
- language_selector::init(cx);
- theme_selector::init(cx);
- language_tools::init(cx);
- call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
- notifications::init(app_state.client.clone(), app_state.user_store.clone(), cx);
- collab_ui::init(&app_state, cx);
- feedback::init(cx);
- welcome::init(cx);
-
- cx.set_menus(app_menus());
- initialize_workspace(app_state.clone(), cx);
-
- if stdout_is_a_pty() {
- cx.activate(true);
- let urls = collect_url_args();
- if !urls.is_empty() {
- listener.open_urls(&urls)
- }
- } else {
- upload_previous_panics(http.clone(), cx);
-
- // TODO Development mode that forces the CLI mode usually runs Zed binary as is instead
- // of an *app, hence gets no specific callbacks run. Emulate them here, if needed.
- if std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_some()
- && !listener.triggered.load(Ordering::Acquire)
- {
- listener.open_urls(&collect_url_args())
- }
- }
-
- let mut triggered_authentication = false;
-
- fn open_paths_and_log_errs(
- paths: &[PathBuf],
- app_state: &Arc<AppState>,
- cx: &mut AppContext,
- ) {
- let task = workspace::open_paths(&paths, &app_state, None, cx);
- cx.spawn(|_| async move {
- if let Some((_window, results)) = task.await.log_err() {
- for result in results {
- if let Some(Err(e)) = result {
- log::error!("Error opening path: {}", e);
- }
- }
- }
- })
- .detach();
- }
-
- match open_rx.try_next() {
- Ok(Some(OpenRequest::Paths { paths })) => {
- open_paths_and_log_errs(&paths, &app_state, cx)
- }
- Ok(Some(OpenRequest::CliConnection { connection })) => {
- let app_state = app_state.clone();
- cx.spawn(move |cx| handle_cli_connection(connection, app_state, cx))
- .detach();
- }
- Ok(Some(OpenRequest::JoinChannel { channel_id })) => {
- triggered_authentication = true;
- let app_state = app_state.clone();
- let client = client.clone();
- cx.spawn(|cx| async move {
- // ignore errors here, we'll show a generic "not signed in"
- let _ = authenticate(client, &cx).await;
- cx.update(|cx| workspace::join_channel(channel_id, app_state, None, cx))?
- .await?;
- anyhow::Ok(())
- })
- .detach_and_log_err(cx);
- }
- Ok(Some(OpenRequest::OpenChannelNotes { channel_id })) => {
- triggered_authentication = true;
- let app_state = app_state.clone();
- let client = client.clone();
- cx.spawn(|mut cx| async move {
- // ignore errors here, we'll show a generic "not signed in"
- let _ = authenticate(client, &cx).await;
- let workspace_window =
- workspace::get_any_active_workspace(app_state, cx.clone()).await?;
- let _ = workspace_window
- .update(&mut cx, |_, cx| {
- ChannelView::open(channel_id, cx.view().clone(), cx)
- })?
- .await?;
- anyhow::Ok(())
- })
- .detach_and_log_err(cx);
- }
- Ok(None) | Err(_) => cx
- .spawn({
- let app_state = app_state.clone();
- |cx| async move { restore_or_create_workspace(&app_state, cx).await }
- })
- .detach(),
- }
-
- let app_state = app_state.clone();
- cx.spawn(move |cx| async move {
- while let Some(request) = open_rx.next().await {
- match request {
- OpenRequest::Paths { paths } => {
- cx.update(|cx| open_paths_and_log_errs(&paths, &app_state, cx))
- .ok();
- }
- OpenRequest::CliConnection { connection } => {
- let app_state = app_state.clone();
- cx.spawn(move |cx| {
- handle_cli_connection(connection, app_state.clone(), cx)
- })
- .detach();
- }
- OpenRequest::JoinChannel { channel_id } => {
- let app_state = app_state.clone();
- cx.update(|mut cx| {
- cx.spawn(|cx| async move {
- cx.update(|cx| {
- workspace::join_channel(channel_id, app_state, None, cx)
- })?
- .await?;
- anyhow::Ok(())
- })
- .detach_and_log_err(&mut cx);
- })
- .log_err();
- }
- OpenRequest::OpenChannelNotes { channel_id } => {
- let app_state = app_state.clone();
- let open_notes_task = cx.spawn(|mut cx| async move {
- let workspace_window =
- workspace::get_any_active_workspace(app_state, cx.clone()).await?;
- let _ = workspace_window
- .update(&mut cx, |_, cx| {
- ChannelView::open(channel_id, cx.view().clone(), cx)
- })?
- .await?;
- anyhow::Ok(())
- });
- cx.update(|cx| open_notes_task.detach_and_log_err(cx))
- .log_err();
- }
- }
- }
- })
- .detach();
-
- if !triggered_authentication {
- cx.spawn(|cx| async move { authenticate(client, &cx).await })
- .detach_and_log_err(cx);
- }
- });
-}
-
-async fn authenticate(client: Arc<Client>, cx: &AsyncAppContext) -> Result<()> {
- if stdout_is_a_pty() {
- if client::IMPERSONATE_LOGIN.is_some() {
- client.authenticate_and_connect(false, &cx).await?;
- }
- } else if client.has_keychain_credentials(&cx) {
- client.authenticate_and_connect(true, &cx).await?;
- }
- Ok::<_, anyhow::Error>(())
-}
-
-async fn installation_id() -> Result<(String, bool)> {
- let legacy_key_name = "device_id".to_string();
- let key_name = "installation_id".to_string();
-
- // Migrate legacy key to new key
- if let Ok(Some(installation_id)) = KEY_VALUE_STORE.read_kvp(&legacy_key_name) {
- KEY_VALUE_STORE
- .write_kvp(key_name, installation_id.clone())
- .await?;
- KEY_VALUE_STORE.delete_kvp(legacy_key_name).await?;
- return Ok((installation_id, true));
- }
-
- if let Ok(Some(installation_id)) = KEY_VALUE_STORE.read_kvp(&key_name) {
- return Ok((installation_id, true));
- }
-
- let installation_id = Uuid::new_v4().to_string();
-
- KEY_VALUE_STORE
- .write_kvp(key_name, installation_id.clone())
- .await?;
-
- Ok((installation_id, false))
-}
-
-async fn restore_or_create_workspace(app_state: &Arc<AppState>, cx: AsyncAppContext) {
- async_maybe!({
- if let Some(location) = workspace::last_opened_workspace_paths().await {
- cx.update(|cx| workspace::open_paths(location.paths().as_ref(), app_state, None, cx))?
- .await
- .log_err();
- } else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) {
- cx.update(|cx| show_welcome_view(app_state, cx)).log_err();
- } else {
- cx.update(|cx| {
- workspace::open_new(app_state, cx, |workspace, cx| {
- Editor::new_file(workspace, &Default::default(), cx)
- })
- .detach();
- })?;
- }
- anyhow::Ok(())
- })
- .await
- .log_err();
-}
-
-fn init_paths() {
- std::fs::create_dir_all(&*util::paths::CONFIG_DIR).expect("could not create config path");
- std::fs::create_dir_all(&*util::paths::LANGUAGES_DIR).expect("could not create languages path");
- std::fs::create_dir_all(&*util::paths::DB_DIR).expect("could not create database path");
- std::fs::create_dir_all(&*util::paths::LOGS_DIR).expect("could not create logs path");
-}
-
-fn init_logger() {
- if stdout_is_a_pty() {
- env_logger::init();
- } else {
- let level = LevelFilter::Info;
-
- // Prevent log file from becoming too large.
- const KIB: u64 = 1024;
- const MIB: u64 = 1024 * KIB;
- const MAX_LOG_BYTES: u64 = MIB;
- if std::fs::metadata(&*paths::LOG).map_or(false, |metadata| metadata.len() > MAX_LOG_BYTES)
- {
- let _ = std::fs::rename(&*paths::LOG, &*paths::OLD_LOG);
- }
-
- let log_file = OpenOptions::new()
- .create(true)
- .append(true)
- .open(&*paths::LOG)
- .expect("could not open logfile");
-
- let config = ConfigBuilder::new()
- .set_time_format_str("%Y-%m-%dT%T") //All timestamps are UTC
- .build();
-
- simplelog::WriteLogger::init(level, config, log_file).expect("could not initialize logger");
- }
-}
-
-#[derive(Serialize, Deserialize)]
-struct LocationData {
- file: String,
- line: u32,
-}
-
-#[derive(Serialize, Deserialize)]
-struct Panic {
- thread: String,
- payload: String,
- #[serde(skip_serializing_if = "Option::is_none")]
- location_data: Option<LocationData>,
- backtrace: Vec<String>,
- app_version: String,
- release_channel: String,
- os_name: String,
- os_version: Option<String>,
- architecture: String,
- panicked_on: i64,
- #[serde(skip_serializing_if = "Option::is_none")]
- installation_id: Option<String>,
- session_id: String,
-}
-
-#[derive(Serialize)]
-struct PanicRequest {
- panic: Panic,
- token: String,
-}
-
-static PANIC_COUNT: AtomicU32 = AtomicU32::new(0);
-
-fn init_panic_hook(app: &App, installation_id: Option<String>, session_id: String) {
- let is_pty = stdout_is_a_pty();
- let app_metadata = app.metadata();
-
- panic::set_hook(Box::new(move |info| {
- let prior_panic_count = PANIC_COUNT.fetch_add(1, Ordering::SeqCst);
- if prior_panic_count > 0 {
- // Give the panic-ing thread time to write the panic file
- loop {
- std::thread::yield_now();
- }
- }
-
- let thread = thread::current();
- let thread_name = thread.name().unwrap_or("<unnamed>");
-
- let payload = info
- .payload()
- .downcast_ref::<&str>()
- .map(|s| s.to_string())
- .or_else(|| info.payload().downcast_ref::<String>().map(|s| s.clone()))
- .unwrap_or_else(|| "Box<Any>".to_string());
-
- if *util::channel::RELEASE_CHANNEL == ReleaseChannel::Dev {
- let location = info.location().unwrap();
- let backtrace = Backtrace::new();
- eprintln!(
- "Thread {:?} panicked with {:?} at {}:{}:{}\n{:?}",
- thread_name,
- payload,
- location.file(),
- location.line(),
- location.column(),
- backtrace,
- );
- std::process::exit(-1);
- }
-
- let app_version = client::ZED_APP_VERSION
- .or(app_metadata.app_version)
- .map_or("dev".to_string(), |v| v.to_string());
-
- let backtrace = Backtrace::new();
- let mut backtrace = backtrace
- .frames()
- .iter()
- .filter_map(|frame| Some(format!("{:#}", frame.symbols().first()?.name()?)))
- .collect::<Vec<_>>();
-
- // Strip out leading stack frames for rust panic-handling.
- if let Some(ix) = backtrace
- .iter()
- .position(|name| name == "rust_begin_unwind")
- {
- backtrace.drain(0..=ix);
- }
-
- let panic_data = Panic {
- thread: thread_name.into(),
- payload: payload.into(),
- location_data: info.location().map(|location| LocationData {
- file: location.file().into(),
- line: location.line(),
- }),
- app_version: app_version.clone(),
- release_channel: RELEASE_CHANNEL.display_name().into(),
- os_name: app_metadata.os_name.into(),
- os_version: app_metadata
- .os_version
- .as_ref()
- .map(SemanticVersion::to_string),
- architecture: env::consts::ARCH.into(),
- panicked_on: Utc::now().timestamp_millis(),
- backtrace,
- installation_id: installation_id.clone(),
- session_id: session_id.clone(),
- };
-
- if let Some(panic_data_json) = serde_json::to_string_pretty(&panic_data).log_err() {
- log::error!("{}", panic_data_json);
- }
-
- if !is_pty {
- if let Some(panic_data_json) = serde_json::to_string(&panic_data).log_err() {
- let timestamp = chrono::Utc::now().format("%Y_%m_%d %H_%M_%S").to_string();
- let panic_file_path = paths::LOGS_DIR.join(format!("zed-{}.panic", timestamp));
- let panic_file = std::fs::OpenOptions::new()
- .append(true)
- .create(true)
- .open(&panic_file_path)
- .log_err();
- if let Some(mut panic_file) = panic_file {
- writeln!(&mut panic_file, "{}", panic_data_json).log_err();
- panic_file.flush().log_err();
- }
- }
- }
-
- std::process::abort();
- }));
-}
-
-fn upload_previous_panics(http: Arc<dyn HttpClient>, cx: &mut AppContext) {
- let telemetry_settings = *client::TelemetrySettings::get_global(cx);
-
- cx.background_executor()
- .spawn(async move {
- let panic_report_url = format!("{}/api/panic", &*client::ZED_SERVER_URL);
- let mut children = smol::fs::read_dir(&*paths::LOGS_DIR).await?;
- while let Some(child) = children.next().await {
- let child = child?;
- let child_path = child.path();
-
- if child_path.extension() != Some(OsStr::new("panic")) {
- continue;
- }
- let filename = if let Some(filename) = child_path.file_name() {
- filename.to_string_lossy()
- } else {
- continue;
- };
-
- if !filename.starts_with("zed") {
- continue;
- }
-
- if telemetry_settings.diagnostics {
- let panic_file_content = smol::fs::read_to_string(&child_path)
- .await
- .context("error reading panic file")?;
-
- let panic = serde_json::from_str(&panic_file_content)
- .ok()
- .or_else(|| {
- panic_file_content
- .lines()
- .next()
- .and_then(|line| serde_json::from_str(line).ok())
- })
- .unwrap_or_else(|| {
- log::error!(
- "failed to deserialize panic file {:?}",
- panic_file_content
- );
- None
- });
-
- if let Some(panic) = panic {
- let body = serde_json::to_string(&PanicRequest {
- panic,
- token: client::ZED_SECRET_CLIENT_TOKEN.into(),
- })
- .unwrap();
-
- let request = Request::post(&panic_report_url)
- .redirect_policy(isahc::config::RedirectPolicy::Follow)
- .header("Content-Type", "application/json")
- .body(body.into())?;
- let response = http.send(request).await.context("error sending panic")?;
- if !response.status().is_success() {
- log::error!("Error uploading panic to server: {}", response.status());
- }
- }
- }
-
- // We've done what we can, delete the file
- std::fs::remove_file(child_path)
- .context("error removing panic")
- .log_err();
- }
- Ok::<_, anyhow::Error>(())
- })
- .detach_and_log_err(cx);
-}
-
-async fn load_login_shell_environment() -> Result<()> {
- let marker = "ZED_LOGIN_SHELL_START";
- let shell = env::var("SHELL").context(
- "SHELL environment variable is not assigned so we can't source login environment variables",
- )?;
- let output = Command::new(&shell)
- .args(["-lic", &format!("echo {marker} && /usr/bin/env -0")])
- .output()
- .await
- .context("failed to spawn login shell to source login environment variables")?;
- if !output.status.success() {
- Err(anyhow!("login shell exited with error"))?;
- }
-
- let stdout = String::from_utf8_lossy(&output.stdout);
-
- if let Some(env_output_start) = stdout.find(marker) {
- let env_output = &stdout[env_output_start + marker.len()..];
- for line in env_output.split_terminator('\0') {
- if let Some(separator_index) = line.find('=') {
- let key = &line[..separator_index];
- let value = &line[separator_index + 1..];
- env::set_var(key, value);
- }
- }
- log::info!(
- "set environment variables from shell:{}, path:{}",
- shell,
- env::var("PATH").unwrap_or_default(),
- );
- }
-
- Ok(())
-}
-
-fn stdout_is_a_pty() -> bool {
- std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_none() && std::io::stdout().is_terminal()
-}
-
-fn collect_url_args() -> Vec<String> {
- env::args()
- .skip(1)
- .filter_map(|arg| match std::fs::canonicalize(Path::new(&arg)) {
- Ok(path) => Some(format!("file://{}", path.to_string_lossy())),
- Err(error) => {
- if let Some(_) = parse_zed_link(&arg) {
- Some(arg)
- } else {
- log::error!("error parsing path argument: {}", error);
- None
- }
- }
- })
- .collect()
-}
-
-fn load_embedded_fonts(cx: &AppContext) {
- let asset_source = cx.asset_source();
- let font_paths = asset_source.list("fonts").unwrap();
- let embedded_fonts = Mutex::new(Vec::new());
- let executor = cx.background_executor();
-
- executor.block(executor.scoped(|scope| {
- for font_path in &font_paths {
- if !font_path.ends_with(".ttf") {
- continue;
- }
-
- scope.spawn(async {
- let font_bytes = asset_source.load(font_path).unwrap().to_vec();
- embedded_fonts.lock().push(Arc::from(font_bytes));
- });
- }
- }));
-
- cx.text_system()
- .add_fonts(&embedded_fonts.into_inner())
- .unwrap();
-}
-
-#[cfg(debug_assertions)]
-async fn watch_languages(fs: Arc<dyn fs::Fs>, languages: Arc<LanguageRegistry>) -> Option<()> {
- use std::time::Duration;
-
- let mut events = fs
- .watch(
- "crates/zed2/src/languages".as_ref(),
- Duration::from_millis(100),
- )
- .await;
- while (events.next().await).is_some() {
- languages.reload();
- }
- Some(())
-}
-
-#[cfg(debug_assertions)]
-fn watch_file_types(fs: Arc<dyn fs::Fs>, cx: &mut AppContext) {
- use std::time::Duration;
-
- cx.spawn(|cx| async move {
- let mut events = fs
- .watch(
- "assets/icons/file_icons/file_types.json".as_ref(),
- Duration::from_millis(100),
- )
- .await;
- while (events.next().await).is_some() {
- cx.update(|cx| {
- cx.update_global(|file_types, _| {
- *file_types = project_panel::file_associations::FileAssociations::new(Assets);
- });
- })
- .ok();
- }
- })
- .detach()
-}
-
-#[cfg(not(debug_assertions))]
-async fn watch_languages(_: Arc<dyn fs::Fs>, _: Arc<LanguageRegistry>) -> Option<()> {
- None
-}
-
-#[cfg(not(debug_assertions))]
-fn watch_file_types(_fs: Arc<dyn fs::Fs>, _cx: &mut AppContext) {}
@@ -1,105 +0,0 @@
-use std::{
- io::{Read, Write},
- net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener, TcpStream},
- thread,
- time::Duration,
-};
-
-use util::channel::ReleaseChannel;
-
-const LOCALHOST: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
-const CONNECT_TIMEOUT: Duration = Duration::from_millis(10);
-const RECEIVE_TIMEOUT: Duration = Duration::from_millis(35);
-const SEND_TIMEOUT: Duration = Duration::from_millis(20);
-
-fn address() -> SocketAddr {
- let port = match *util::channel::RELEASE_CHANNEL {
- ReleaseChannel::Dev => 43737,
- ReleaseChannel::Preview => 43738,
- ReleaseChannel::Stable => 43739,
- ReleaseChannel::Nightly => 43740,
- };
-
- SocketAddr::V4(SocketAddrV4::new(LOCALHOST, port))
-}
-
-fn instance_handshake() -> &'static str {
- match *util::channel::RELEASE_CHANNEL {
- ReleaseChannel::Dev => "Zed Editor Dev Instance Running",
- ReleaseChannel::Nightly => "Zed Editor Nightly Instance Running",
- ReleaseChannel::Preview => "Zed Editor Preview Instance Running",
- ReleaseChannel::Stable => "Zed Editor Stable Instance Running",
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum IsOnlyInstance {
- Yes,
- No,
-}
-
-pub fn ensure_only_instance() -> IsOnlyInstance {
- if *db::ZED_STATELESS || *util::channel::RELEASE_CHANNEL == ReleaseChannel::Dev {
- return IsOnlyInstance::Yes;
- }
-
- if check_got_handshake() {
- return IsOnlyInstance::No;
- }
-
- let listener = match TcpListener::bind(address()) {
- Ok(listener) => listener,
-
- Err(err) => {
- log::warn!("Error binding to single instance port: {err}");
- if check_got_handshake() {
- return IsOnlyInstance::No;
- }
-
- // Avoid failing to start when some other application by chance already has
- // a claim on the port. This is sub-par as any other instance that gets launched
- // will be unable to communicate with this instance and will duplicate
- log::warn!("Backup handshake request failed, continuing without handshake");
- return IsOnlyInstance::Yes;
- }
- };
-
- thread::spawn(move || {
- for stream in listener.incoming() {
- let mut stream = match stream {
- Ok(stream) => stream,
- Err(_) => return,
- };
-
- _ = stream.set_nodelay(true);
- _ = stream.set_read_timeout(Some(SEND_TIMEOUT));
- _ = stream.write_all(instance_handshake().as_bytes());
- }
- });
-
- IsOnlyInstance::Yes
-}
-
-fn check_got_handshake() -> bool {
- match TcpStream::connect_timeout(&address(), CONNECT_TIMEOUT) {
- Ok(mut stream) => {
- let mut buf = vec![0u8; instance_handshake().len()];
-
- stream.set_read_timeout(Some(RECEIVE_TIMEOUT)).unwrap();
- if let Err(err) = stream.read_exact(&mut buf) {
- log::warn!("Connected to single instance port but failed to read: {err}");
- return false;
- }
-
- if buf == instance_handshake().as_bytes() {
- log::info!("Got instance handshake");
- return true;
- }
-
- log::warn!("Got wrong instance handshake value");
- false
- }
-
- Err(_) => false,
- }
-}
@@ -1,303 +0,0 @@
-use anyhow::{anyhow, Context, Result};
-use cli::{ipc, IpcHandshake};
-use cli::{ipc::IpcSender, CliRequest, CliResponse};
-use editor::scroll::autoscroll::Autoscroll;
-use editor::Editor;
-use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
-use futures::channel::{mpsc, oneshot};
-use futures::{FutureExt, SinkExt, StreamExt};
-use gpui::AsyncAppContext;
-use language::{Bias, Point};
-use std::collections::HashMap;
-use std::ffi::OsStr;
-use std::os::unix::prelude::OsStrExt;
-use std::path::Path;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::thread;
-use std::time::Duration;
-use std::{path::PathBuf, sync::atomic::AtomicBool};
-use util::channel::parse_zed_link;
-use util::paths::PathLikeWithPosition;
-use util::ResultExt;
-use workspace::AppState;
-
-pub enum OpenRequest {
- Paths {
- paths: Vec<PathBuf>,
- },
- CliConnection {
- connection: (mpsc::Receiver<CliRequest>, IpcSender<CliResponse>),
- },
- JoinChannel {
- channel_id: u64,
- },
- OpenChannelNotes {
- channel_id: u64,
- },
-}
-
-pub struct OpenListener {
- tx: UnboundedSender<OpenRequest>,
- pub triggered: AtomicBool,
-}
-
-impl OpenListener {
- pub fn new() -> (Self, UnboundedReceiver<OpenRequest>) {
- let (tx, rx) = mpsc::unbounded();
- (
- OpenListener {
- tx,
- triggered: AtomicBool::new(false),
- },
- rx,
- )
- }
-
- pub fn open_urls(&self, urls: &[String]) {
- self.triggered.store(true, Ordering::Release);
- let request = if let Some(server_name) =
- urls.first().and_then(|url| url.strip_prefix("zed-cli://"))
- {
- self.handle_cli_connection(server_name)
- } else if let Some(request_path) = urls.first().and_then(|url| parse_zed_link(url)) {
- self.handle_zed_url_scheme(request_path)
- } else {
- self.handle_file_urls(urls)
- };
-
- if let Some(request) = request {
- self.tx
- .unbounded_send(request)
- .map_err(|_| anyhow!("no listener for open requests"))
- .log_err();
- }
- }
-
- fn handle_cli_connection(&self, server_name: &str) -> Option<OpenRequest> {
- if let Some(connection) = connect_to_cli(server_name).log_err() {
- return Some(OpenRequest::CliConnection { connection });
- }
-
- None
- }
-
- fn handle_zed_url_scheme(&self, request_path: &str) -> Option<OpenRequest> {
- let mut parts = request_path.split("/");
- if parts.next() == Some("channel") {
- if let Some(slug) = parts.next() {
- if let Some(id_str) = slug.split("-").last() {
- if let Ok(channel_id) = id_str.parse::<u64>() {
- if Some("notes") == parts.next() {
- return Some(OpenRequest::OpenChannelNotes { channel_id });
- } else {
- return Some(OpenRequest::JoinChannel { channel_id });
- }
- }
- }
- }
- }
- log::error!("invalid zed url: {}", request_path);
- None
- }
-
- fn handle_file_urls(&self, urls: &[String]) -> Option<OpenRequest> {
- let paths: Vec<_> = urls
- .iter()
- .flat_map(|url| url.strip_prefix("file://"))
- .map(|url| {
- let decoded = urlencoding::decode_binary(url.as_bytes());
- PathBuf::from(OsStr::from_bytes(decoded.as_ref()))
- })
- .collect();
-
- Some(OpenRequest::Paths { paths })
- }
-}
-
-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))
-}
-
-pub 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 mut caret_positions = HashMap::new();
-
- let paths = if paths.is_empty() {
- workspace::last_opened_workspace_paths()
- .await
- .map(|location| location.paths().to_vec())
- .unwrap_or_default()
- } else {
- paths
- .into_iter()
- .filter_map(|path_with_position_string| {
- let path_with_position = PathLikeWithPosition::parse_str(
- &path_with_position_string,
- |path_str| {
- Ok::<_, std::convert::Infallible>(
- Path::new(path_str).to_path_buf(),
- )
- },
- )
- .expect("Infallible");
- let path = path_with_position.path_like;
- if let Some(row) = path_with_position.row {
- if path.is_file() {
- let row = row.saturating_sub(1);
- let col =
- path_with_position.column.unwrap_or(0).saturating_sub(1);
- caret_positions.insert(path.clone(), Point::new(row, col));
- }
- }
- Some(path)
- })
- .collect()
- };
-
- let mut errored = false;
-
- match cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx)) {
- Ok(task) => match task.await {
- Ok((workspace, items)) => {
- let mut item_release_futures = Vec::new();
-
- for (item, path) in items.into_iter().zip(&paths) {
- match item {
- Some(Ok(item)) => {
- if let Some(point) = caret_positions.remove(path) {
- if let Some(active_editor) = item.downcast::<Editor>() {
- workspace
- .update(&mut cx, |_, cx| {
- active_editor.update(cx, |editor, cx| {
- let snapshot = editor
- .snapshot(cx)
- .display_snapshot;
- let point = snapshot
- .buffer_snapshot
- .clip_point(point, Bias::Left);
- editor.change_selections(
- Some(Autoscroll::center()),
- cx,
- |s| s.select_ranges([point..point]),
- );
- });
- })
- .log_err();
- }
- }
-
- cx.update(|cx| {
- let released = oneshot::channel();
- item.on_release(
- cx,
- Box::new(move |_| {
- let _ = released.0.send(());
- }),
- )
- .detach();
- item_release_futures.push(released.1);
- })
- .log_err();
- }
- Some(Err(err)) => {
- responses
- .send(CliResponse::Stderr {
- message: format!(
- "error opening {:?}: {}",
- path, err
- ),
- })
- .log_err();
- errored = true;
- }
- None => {}
- }
- }
-
- if wait {
- let background = cx.background_executor().clone();
- let wait = async move {
- if paths.is_empty() {
- let (done_tx, done_rx) = oneshot::channel();
- let _subscription = workspace.update(&mut cx, |_, cx| {
- cx.on_release(move |_, _, _| {
- let _ = done_tx.send(());
- })
- });
- let _ = done_rx.await;
- } else {
- let _ = futures::future::try_join_all(item_release_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;
- }
- }
- }
- }
- }
- }
- Err(error) => {
- errored = true;
- responses
- .send(CliResponse::Stderr {
- message: format!("error opening {:?}: {}", paths, error),
- })
- .log_err();
- }
- },
- Err(_) => errored = true,
- }
-
- responses
- .send(CliResponse::Exit {
- status: i32::from(errored),
- })
- .log_err();
- }
- }
- }
-}
@@ -1,2598 +0,0 @@
-mod app_menus;
-mod assets;
-pub mod languages;
-mod only_instance;
-mod open_listener;
-
-pub use app_menus::*;
-pub use assets::*;
-use assistant::AssistantPanel;
-use breadcrumbs::Breadcrumbs;
-use collections::VecDeque;
-use editor::{Editor, MultiBuffer};
-use gpui::{
- actions, point, px, AppContext, Context, FocusableView, PromptLevel, TitlebarOptions, View,
- ViewContext, VisualContext, WindowBounds, WindowKind, WindowOptions,
-};
-pub use only_instance::*;
-pub use open_listener::*;
-
-use anyhow::{anyhow, Context as _};
-use futures::{channel::mpsc, StreamExt};
-use project_panel::ProjectPanel;
-use quick_action_bar::QuickActionBar;
-use search::project_search::ProjectSearchBar;
-use settings::{initial_local_settings_content, load_default_keymap, KeymapFile, Settings};
-use std::{borrow::Cow, ops::Deref, sync::Arc};
-use terminal_view::terminal_panel::TerminalPanel;
-use util::{
- asset_str,
- channel::{AppCommitSha, ReleaseChannel},
- paths::{self, LOCAL_SETTINGS_RELATIVE_PATH},
- ResultExt,
-};
-use uuid::Uuid;
-use workspace::Pane;
-use workspace::{
- create_and_open_local_file, notifications::simple_message_notification::MessageNotification,
- open_new, AppState, NewFile, NewWindow, Workspace, WorkspaceSettings,
-};
-use zed_actions::{OpenBrowser, OpenSettings, OpenZedURL, Quit};
-
-actions!(
- zed,
- [
- About,
- DebugElements,
- DecreaseBufferFontSize,
- Hide,
- HideOthers,
- IncreaseBufferFontSize,
- Minimize,
- OpenDefaultKeymap,
- OpenDefaultSettings,
- OpenKeymap,
- OpenLicenses,
- OpenLocalSettings,
- OpenLog,
- OpenTelemetryLog,
- ResetBufferFontSize,
- ResetDatabase,
- ShowAll,
- ToggleFullScreen,
- Zoom,
- ]
-);
-
-pub fn build_window_options(
- bounds: Option<WindowBounds>,
- display_uuid: Option<Uuid>,
- cx: &mut AppContext,
-) -> WindowOptions {
- let bounds = bounds.unwrap_or(WindowBounds::Maximized);
- let display = display_uuid.and_then(|uuid| {
- cx.displays()
- .into_iter()
- .find(|display| display.uuid().ok() == Some(uuid))
- });
-
- WindowOptions {
- bounds,
- titlebar: Some(TitlebarOptions {
- title: None,
- appears_transparent: true,
- traffic_light_position: Some(point(px(8.), px(8.))),
- }),
- center: false,
- focus: false,
- show: false,
- kind: WindowKind::Normal,
- is_movable: true,
- display_id: display.map(|display| display.id()),
- }
-}
-
-pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
- cx.observe_new_views(move |workspace: &mut Workspace, cx| {
- let workspace_handle = cx.view().clone();
- let center_pane = workspace.active_pane().clone();
- initialize_pane(workspace, ¢er_pane, cx);
- cx.subscribe(&workspace_handle, {
- move |workspace, _, event, cx| {
- if let workspace::Event::PaneAdded(pane) = event {
- initialize_pane(workspace, pane, cx);
- }
- }
- })
- .detach();
-
- // cx.emit(workspace2::Event::PaneAdded(
- // workspace.active_pane().clone(),
- // ));
-
- // let collab_titlebar_item =
- // cx.add_view(|cx| CollabTitlebarItem::new(workspace, &workspace_handle, cx));
- // workspace.set_titlebar_item(collab_titlebar_item.into_any(), cx);
-
- let copilot =
- cx.new_view(|cx| copilot_button::CopilotButton::new(app_state.fs.clone(), cx));
- let diagnostic_summary =
- cx.new_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx));
- let activity_indicator =
- activity_indicator::ActivityIndicator::new(workspace, app_state.languages.clone(), cx);
- let active_buffer_language =
- cx.new_view(|_| language_selector::ActiveBufferLanguage::new(workspace));
- let vim_mode_indicator = cx.new_view(|cx| vim::ModeIndicator::new(cx));
- let feedback_button =
- cx.new_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace));
- let cursor_position = cx.new_view(|_| editor::items::CursorPosition::new());
- workspace.status_bar().update(cx, |status_bar, cx| {
- status_bar.add_left_item(diagnostic_summary, cx);
- status_bar.add_left_item(activity_indicator, cx);
- status_bar.add_right_item(feedback_button, cx);
- // status_bar.add_right_item(copilot, cx);
- status_bar.add_right_item(copilot, cx);
- status_bar.add_right_item(active_buffer_language, cx);
- status_bar.add_right_item(vim_mode_indicator, cx);
- status_bar.add_right_item(cursor_position, cx);
- });
-
- auto_update::notify_of_any_new_update(cx);
-
- vim::observe_keystrokes(cx);
-
- let handle = cx.view().downgrade();
- cx.on_window_should_close(move |cx| {
- handle
- .update(cx, |workspace, cx| {
- workspace.close_window(&Default::default(), cx);
- false
- })
- .unwrap_or(true)
- });
-
- cx.spawn(|workspace_handle, mut cx| async move {
- let project_panel = ProjectPanel::load(workspace_handle.clone(), cx.clone());
- let terminal_panel = TerminalPanel::load(workspace_handle.clone(), cx.clone());
- let assistant_panel = AssistantPanel::load(workspace_handle.clone(), cx.clone());
- let channels_panel =
- collab_ui::collab_panel::CollabPanel::load(workspace_handle.clone(), cx.clone());
- let chat_panel =
- collab_ui::chat_panel::ChatPanel::load(workspace_handle.clone(), cx.clone());
- let notification_panel = collab_ui::notification_panel::NotificationPanel::load(
- workspace_handle.clone(),
- cx.clone(),
- );
- let (
- project_panel,
- terminal_panel,
- assistant_panel,
- channels_panel,
- chat_panel,
- notification_panel,
- ) = futures::try_join!(
- project_panel,
- terminal_panel,
- assistant_panel,
- channels_panel,
- chat_panel,
- notification_panel,
- )?;
-
- workspace_handle.update(&mut cx, |workspace, cx| {
- workspace.add_panel(project_panel, cx);
- workspace.add_panel(terminal_panel, cx);
- workspace.add_panel(assistant_panel, cx);
- workspace.add_panel(channels_panel, cx);
- workspace.add_panel(chat_panel, cx);
- workspace.add_panel(notification_panel, cx);
-
- // if !was_deserialized
- // && workspace
- // .project()
- // .read(cx)
- // .visible_worktrees(cx)
- // .any(|tree| {
- // tree.read(cx)
- // .root_entry()
- // .map_or(false, |entry| entry.is_dir())
- // })
- // {
- // workspace.toggle_dock(project_panel_position, cx);
- // }
- cx.focus_self();
- })
- })
- .detach();
-
- workspace
- .register_action(about)
- .register_action(|_, _: &Hide, cx| {
- cx.hide();
- })
- .register_action(|_, _: &HideOthers, cx| {
- cx.hide_other_apps();
- })
- .register_action(|_, _: &ShowAll, cx| {
- cx.unhide_other_apps();
- })
- .register_action(|_, _: &Minimize, cx| {
- cx.minimize_window();
- })
- .register_action(|_, _: &Zoom, cx| {
- cx.zoom_window();
- })
- .register_action(|_, _: &ToggleFullScreen, cx| {
- cx.toggle_full_screen();
- })
- .register_action(quit)
- .register_action(|_, action: &OpenZedURL, cx| {
- cx.global::<Arc<OpenListener>>()
- .open_urls(&[action.url.clone()])
- })
- .register_action(|_, action: &OpenBrowser, cx| cx.open_url(&action.url))
- .register_action(move |_, _: &IncreaseBufferFontSize, cx| {
- theme::adjust_font_size(cx, |size| *size += px(1.0))
- })
- .register_action(move |_, _: &DecreaseBufferFontSize, cx| {
- theme::adjust_font_size(cx, |size| *size -= px(1.0))
- })
- .register_action(move |_, _: &ResetBufferFontSize, cx| theme::reset_font_size(cx))
- .register_action(|_, _: &install_cli::Install, cx| {
- cx.spawn(|_, cx| async move {
- install_cli::install_cli(cx.deref())
- .await
- .context("error creating CLI symlink")
- })
- .detach_and_log_err(cx);
- })
- .register_action(|workspace, _: &OpenLog, cx| {
- open_log_file(workspace, cx);
- })
- .register_action(|workspace, _: &OpenLicenses, cx| {
- open_bundled_file(
- workspace,
- asset_str::<Assets>("licenses.md"),
- "Open Source License Attribution",
- "Markdown",
- cx,
- );
- })
- .register_action(
- move |workspace: &mut Workspace,
- _: &OpenTelemetryLog,
- cx: &mut ViewContext<Workspace>| {
- open_telemetry_log_file(workspace, cx);
- },
- )
- .register_action(
- move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
- create_and_open_local_file(&paths::KEYMAP, cx, Default::default)
- .detach_and_log_err(cx);
- },
- )
- .register_action(
- move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
- create_and_open_local_file(&paths::SETTINGS, cx, || {
- settings::initial_user_settings_content().as_ref().into()
- })
- .detach_and_log_err(cx);
- },
- )
- .register_action(open_local_settings_file)
- .register_action(
- move |workspace: &mut Workspace,
- _: &OpenDefaultKeymap,
- cx: &mut ViewContext<Workspace>| {
- open_bundled_file(
- workspace,
- settings::default_keymap(),
- "Default Key Bindings",
- "JSON",
- cx,
- );
- },
- )
- .register_action(
- move |workspace: &mut Workspace,
- _: &OpenDefaultSettings,
- cx: &mut ViewContext<Workspace>| {
- open_bundled_file(
- workspace,
- settings::default_settings(),
- "Default Settings",
- "JSON",
- cx,
- );
- },
- )
- //todo!()
- // cx.add_action({
- // move |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext<Workspace>| {
- // let app_state = workspace.app_state().clone();
- // let markdown = app_state.languages.language_for_name("JSON");
- // let window = cx.window();
- // cx.spawn(|workspace, mut cx| async move {
- // let markdown = markdown.await.log_err();
- // let content = to_string_pretty(&window.debug_elements(&cx).ok_or_else(|| {
- // anyhow!("could not debug elements for window {}", window.id())
- // })?)
- // .unwrap();
- // workspace
- // .update(&mut cx, |workspace, cx| {
- // workspace.with_local_workspace(cx, move |workspace, cx| {
- // let project = workspace.project().clone();
- // let buffer = project
- // .update(cx, |project, cx| {
- // project.create_buffer(&content, markdown, cx)
- // })
- // .expect("creating buffers on a local workspace always succeeds");
- // let buffer = cx.add_model(|cx| {
- // MultiBuffer::singleton(buffer, cx)
- // .with_title("Debug Elements".into())
- // });
- // workspace.add_item(
- // Box::new(cx.add_view(|cx| {
- // Editor::for_multibuffer(buffer, Some(project.clone()), cx)
- // })),
- // cx,
- // );
- // })
- // })?
- // .await
- // })
- // .detach_and_log_err(cx);
- // }
- // });
- // .register_action(
- // |workspace: &mut Workspace,
- // _: &project_panel::ToggleFocus,
- // cx: &mut ViewContext<Workspace>| {
- // workspace.toggle_panel_focus::<ProjectPanel>(cx);
- // },
- // );
- // cx.add_action(
- // |workspace: &mut Workspace,
- // _: &collab_ui::collab_panel::ToggleFocus,
- // cx: &mut ViewContext<Workspace>| {
- // workspace.toggle_panel_focus::<collab_ui::collab_panel::CollabPanel>(cx);
- // },
- // );
- // cx.add_action(
- // |workspace: &mut Workspace,
- // _: &collab_ui::chat_panel::ToggleFocus,
- // cx: &mut ViewContext<Workspace>| {
- // workspace.toggle_panel_focus::<collab_ui::chat_panel::ChatPanel>(cx);
- // },
- // );
- // cx.add_action(
- // |workspace: &mut Workspace,
- // _: &collab_ui::notification_panel::ToggleFocus,
- // cx: &mut ViewContext<Workspace>| {
- // workspace.toggle_panel_focus::<collab_ui::notification_panel::NotificationPanel>(cx);
- // },
- // );
- // cx.add_action(
- // |workspace: &mut Workspace,
- // _: &terminal_panel::ToggleFocus,
- // cx: &mut ViewContext<Workspace>| {
- // workspace.toggle_panel_focus::<TerminalPanel>(cx);
- // },
- // );
- .register_action({
- let app_state = Arc::downgrade(&app_state);
- move |_, _: &NewWindow, cx| {
- if let Some(app_state) = app_state.upgrade() {
- open_new(&app_state, cx, |workspace, cx| {
- Editor::new_file(workspace, &Default::default(), cx)
- })
- .detach();
- }
- }
- })
- .register_action({
- let app_state = Arc::downgrade(&app_state);
- move |_, _: &NewFile, cx| {
- if let Some(app_state) = app_state.upgrade() {
- open_new(&app_state, cx, |workspace, cx| {
- Editor::new_file(workspace, &Default::default(), cx)
- })
- .detach();
- }
- }
- });
-
- workspace.focus_handle(cx).focus(cx);
- //todo!()
- // load_default_keymap(cx);
- })
- .detach();
-}
-
-fn initialize_pane(workspace: &mut Workspace, pane: &View<Pane>, cx: &mut ViewContext<Workspace>) {
- pane.update(cx, |pane, cx| {
- pane.toolbar().update(cx, |toolbar, cx| {
- let breadcrumbs = cx.new_view(|_| Breadcrumbs::new());
- toolbar.add_item(breadcrumbs, cx);
- let buffer_search_bar = cx.new_view(search::BufferSearchBar::new);
- toolbar.add_item(buffer_search_bar.clone(), cx);
-
- let quick_action_bar =
- cx.new_view(|_| QuickActionBar::new(buffer_search_bar, workspace));
- toolbar.add_item(quick_action_bar, cx);
- let diagnostic_editor_controls = cx.new_view(|_| diagnostics::ToolbarControls::new());
- toolbar.add_item(diagnostic_editor_controls, cx);
- let project_search_bar = cx.new_view(|_| ProjectSearchBar::new());
- toolbar.add_item(project_search_bar, cx);
- let lsp_log_item = cx.new_view(|_| language_tools::LspLogToolbarItemView::new());
- toolbar.add_item(lsp_log_item, cx);
- let syntax_tree_item =
- cx.new_view(|_| language_tools::SyntaxTreeToolbarItemView::new());
- toolbar.add_item(syntax_tree_item, cx);
- })
- });
-}
-
-fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext<Workspace>) {
- use std::fmt::Write as _;
-
- let app_name = cx.global::<ReleaseChannel>().display_name();
- let version = env!("CARGO_PKG_VERSION");
- let mut message = format!("{app_name} {version}");
- if let Some(sha) = cx.try_global::<AppCommitSha>() {
- write!(&mut message, "\n\n{}", sha.0).unwrap();
- }
-
- let prompt = cx.prompt(PromptLevel::Info, &message, &["OK"]);
- cx.foreground_executor()
- .spawn(async {
- prompt.await.ok();
- })
- .detach();
-}
-
-fn quit(_: &mut Workspace, _: &Quit, cx: &mut gpui::ViewContext<Workspace>) {
- let should_confirm = WorkspaceSettings::get_global(cx).confirm_quit;
- cx.spawn(|_, mut cx| async move {
- let mut workspace_windows = cx.update(|_, cx| {
- cx.windows()
- .into_iter()
- .filter_map(|window| window.downcast::<Workspace>())
- .collect::<Vec<_>>()
- })?;
-
- // If multiple windows have unsaved changes, and need a save prompt,
- // prompt in the active window before switching to a different window.
- cx.update(|_, cx| {
- workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false));
- })
- .log_err();
-
- if let (true, Some(_)) = (should_confirm, workspace_windows.first().copied()) {
- let answer = cx
- .update(|_, cx| {
- cx.prompt(
- PromptLevel::Info,
- "Are you sure you want to quit?",
- &["Quit", "Cancel"],
- )
- })
- .log_err();
-
- if let Some(answer) = answer {
- let answer = answer.await.ok();
- if answer != Some(0) {
- return Ok(());
- }
- }
- }
-
- // If the user cancels any save prompt, then keep the app open.
- for window in workspace_windows {
- if let Some(should_close) = window
- .update(&mut cx, |workspace, cx| {
- workspace.prepare_to_close(true, cx)
- })
- .log_err()
- {
- if !should_close.await? {
- return Ok(());
- }
- }
- }
- cx.update(|_, cx| {
- cx.quit();
- })?;
- anyhow::Ok(())
- })
- .detach_and_log_err(cx);
-}
-
-fn open_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
- const MAX_LINES: usize = 1000;
- workspace
- .with_local_workspace(cx, move |workspace, cx| {
- let fs = workspace.app_state().fs.clone();
- cx.spawn(|workspace, mut cx| async move {
- let (old_log, new_log) =
- futures::join!(fs.load(&paths::OLD_LOG), fs.load(&paths::LOG));
-
- let mut lines = VecDeque::with_capacity(MAX_LINES);
- for line in old_log
- .iter()
- .flat_map(|log| log.lines())
- .chain(new_log.iter().flat_map(|log| log.lines()))
- {
- if lines.len() == MAX_LINES {
- lines.pop_front();
- }
- lines.push_back(line);
- }
- let log = lines
- .into_iter()
- .flat_map(|line| [line, "\n"])
- .collect::<String>();
-
- workspace
- .update(&mut cx, |workspace, cx| {
- let project = workspace.project().clone();
- let buffer = project
- .update(cx, |project, cx| project.create_buffer("", None, cx))
- .expect("creating buffers on a local workspace always succeeds");
- buffer.update(cx, |buffer, cx| buffer.edit([(0..0, log)], None, cx));
-
- let buffer = cx.new_model(|cx| {
- MultiBuffer::singleton(buffer, cx).with_title("Log".into())
- });
- workspace.add_item(
- Box::new(
- cx.new_view(|cx| {
- Editor::for_multibuffer(buffer, Some(project), cx)
- }),
- ),
- cx,
- );
- })
- .log_err();
- })
- .detach();
- })
- .detach();
-}
-
-pub fn handle_keymap_file_changes(
- mut user_keymap_file_rx: mpsc::UnboundedReceiver<String>,
- cx: &mut AppContext,
-) {
- cx.spawn(move |cx| async move {
- // let mut settings_subscription = None;
- while let Some(user_keymap_content) = user_keymap_file_rx.next().await {
- if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() {
- cx.update(|cx| reload_keymaps(cx, &keymap_content)).ok();
-
- // todo!()
- // let mut old_base_keymap = cx.read(|cx| *settings::get::<BaseKeymap>(cx));
- // drop(settings_subscription);
- // settings_subscription = Some(cx.update(|cx| {
- // cx.observe_global::<SettingsStore, _>(move |cx| {
- // let new_base_keymap = *settings::get::<BaseKeymap>(cx);
- // if new_base_keymap != old_base_keymap {
- // old_base_keymap = new_base_keymap.clone();
- // reload_keymaps(cx, &keymap_content);
- // }
- // })
- // }));
- }
- }
- })
- .detach();
-}
-
-fn reload_keymaps(cx: &mut AppContext, keymap_content: &KeymapFile) {
- // todo!()
- // cx.clear_bindings();
- load_default_keymap(cx);
- keymap_content.clone().add_to_cx(cx).log_err();
- cx.set_menus(app_menus());
-}
-
-fn open_local_settings_file(
- workspace: &mut Workspace,
- _: &OpenLocalSettings,
- cx: &mut ViewContext<Workspace>,
-) {
- let project = workspace.project().clone();
- let worktree = project
- .read(cx)
- .visible_worktrees(cx)
- .find_map(|tree| tree.read(cx).root_entry()?.is_dir().then_some(tree));
- if let Some(worktree) = worktree {
- let tree_id = worktree.read(cx).id();
- cx.spawn(|workspace, mut cx| async move {
- let file_path = &*LOCAL_SETTINGS_RELATIVE_PATH;
-
- if let Some(dir_path) = file_path.parent() {
- if worktree.update(&mut cx, |tree, _| tree.entry_for_path(dir_path).is_none())? {
- project
- .update(&mut cx, |project, cx| {
- project.create_entry((tree_id, dir_path), true, cx)
- })?
- .await
- .context("worktree was removed")?;
- }
- }
-
- if worktree.update(&mut cx, |tree, _| tree.entry_for_path(file_path).is_none())? {
- project
- .update(&mut cx, |project, cx| {
- project.create_entry((tree_id, file_path), false, cx)
- })?
- .await
- .context("worktree was removed")?;
- }
-
- let editor = workspace
- .update(&mut cx, |workspace, cx| {
- workspace.open_path((tree_id, file_path), None, true, cx)
- })?
- .await?
- .downcast::<Editor>()
- .ok_or_else(|| anyhow!("unexpected item type"))?;
-
- editor
- .downgrade()
- .update(&mut cx, |editor, cx| {
- if let Some(buffer) = editor.buffer().read(cx).as_singleton() {
- if buffer.read(cx).is_empty() {
- buffer.update(cx, |buffer, cx| {
- buffer.edit([(0..0, initial_local_settings_content())], None, cx)
- });
- }
- }
- })
- .ok();
-
- anyhow::Ok(())
- })
- .detach();
- } else {
- workspace.show_notification(0, cx, |cx| {
- cx.new_view(|_| MessageNotification::new("This project has no folders open."))
- })
- }
-}
-
-fn open_telemetry_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
- workspace.with_local_workspace(cx, move |workspace, cx| {
- let app_state = workspace.app_state().clone();
- cx.spawn(|workspace, mut cx| async move {
- async fn fetch_log_string(app_state: &Arc<AppState>) -> Option<String> {
- let path = app_state.client.telemetry().log_file_path()?;
- app_state.fs.load(&path).await.log_err()
- }
-
- let log = fetch_log_string(&app_state).await.unwrap_or_else(|| "// No data has been collected yet".to_string());
-
- const MAX_TELEMETRY_LOG_LEN: usize = 5 * 1024 * 1024;
- let mut start_offset = log.len().saturating_sub(MAX_TELEMETRY_LOG_LEN);
- if let Some(newline_offset) = log[start_offset..].find('\n') {
- start_offset += newline_offset + 1;
- }
- let log_suffix = &log[start_offset..];
- let json = app_state.languages.language_for_name("JSON").await.log_err();
-
- workspace.update(&mut cx, |workspace, cx| {
- let project = workspace.project().clone();
- let buffer = project
- .update(cx, |project, cx| project.create_buffer("", None, cx))
- .expect("creating buffers on a local workspace always succeeds");
- buffer.update(cx, |buffer, cx| {
- buffer.set_language(json, cx);
- buffer.edit(
- [(
- 0..0,
- concat!(
- "// Zed collects anonymous usage data to help us understand how people are using the app.\n",
- "// Telemetry can be disabled via the `settings.json` file.\n",
- "// Here is the data that has been reported for the current session:\n",
- "\n"
- ),
- )],
- None,
- cx,
- );
- buffer.edit([(buffer.len()..buffer.len(), log_suffix)], None, cx);
- });
-
- let buffer = cx.new_model(|cx| {
- MultiBuffer::singleton(buffer, cx).with_title("Telemetry Log".into())
- });
- workspace.add_item(
- Box::new(cx.new_view(|cx| Editor::for_multibuffer(buffer, Some(project), cx))),
- cx,
- );
- }).log_err()?;
-
- Some(())
- })
- .detach();
- }).detach();
-}
-
-fn open_bundled_file(
- workspace: &mut Workspace,
- text: Cow<'static, str>,
- title: &'static str,
- language: &'static str,
- cx: &mut ViewContext<Workspace>,
-) {
- let language = workspace.app_state().languages.language_for_name(language);
- cx.spawn(|workspace, mut cx| async move {
- let language = language.await.log_err();
- workspace
- .update(&mut cx, |workspace, cx| {
- workspace.with_local_workspace(cx, |workspace, cx| {
- let project = workspace.project();
- let buffer = project.update(cx, move |project, cx| {
- project
- .create_buffer(text.as_ref(), language, cx)
- .expect("creating buffers on a local workspace always succeeds")
- });
- let buffer = cx.new_model(|cx| {
- MultiBuffer::singleton(buffer, cx).with_title(title.into())
- });
- workspace.add_item(
- Box::new(cx.new_view(|cx| {
- Editor::for_multibuffer(buffer, Some(project.clone()), cx)
- })),
- cx,
- );
- })
- })?
- .await
- })
- .detach_and_log_err(cx);
-}
-
-// todo!()
-// #[cfg(test)]
-// mod tests {
-// use super::*;
-// use assets::Assets;
-// use editor::{scroll::autoscroll::Autoscroll, DisplayPoint, Editor};
-// use fs::{FakeFs, Fs};
-// use gpui::{
-// actions, elements::Empty, executor::Deterministic, Action, AnyElement, AnyWindowHandle,
-// AppContext, AssetSource, Element, Entity, TestAppContext, View, ViewHandle,
-// };
-// use language::LanguageRegistry;
-// use project::{project_settings::ProjectSettings, Project, ProjectPath};
-// use serde_json::json;
-// use settings::{handle_settings_file_changes, watch_config_file, SettingsStore};
-// use std::{
-// collections::HashSet,
-// path::{Path, PathBuf},
-// };
-// use theme::{ThemeRegistry, ThemeSettings};
-// use workspace::{
-// item::{Item, ItemHandle},
-// open_new, open_paths, pane, NewFile, SaveIntent, SplitDirection, WorkspaceHandle,
-// };
-
-// #[gpui::test]
-// async fn test_open_paths_action(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// app_state
-// .fs
-// .as_fake()
-// .insert_tree(
-// "/root",
-// json!({
-// "a": {
-// "aa": null,
-// "ab": null,
-// },
-// "b": {
-// "ba": null,
-// "bb": null,
-// },
-// "c": {
-// "ca": null,
-// "cb": null,
-// },
-// "d": {
-// "da": null,
-// "db": null,
-// },
-// }),
-// )
-// .await;
-
-// cx.update(|cx| {
-// open_paths(
-// &[PathBuf::from("/root/a"), PathBuf::from("/root/b")],
-// &app_state,
-// None,
-// cx,
-// )
-// })
-// .await
-// .unwrap();
-// assert_eq!(cx.windows().len(), 1);
-
-// cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx))
-// .await
-// .unwrap();
-// assert_eq!(cx.windows().len(), 1);
-// let workspace_1 = cx.windows()[0].downcast::<Workspace>().unwrap().root(cx);
-// workspace_1.update(cx, |workspace, cx| {
-// assert_eq!(workspace.worktrees(cx).count(), 2);
-// assert!(workspace.left_dock().read(cx).is_open());
-// assert!(workspace.active_pane().is_focused(cx));
-// });
-
-// cx.update(|cx| {
-// open_paths(
-// &[PathBuf::from("/root/b"), PathBuf::from("/root/c")],
-// &app_state,
-// None,
-// cx,
-// )
-// })
-// .await
-// .unwrap();
-// assert_eq!(cx.windows().len(), 2);
-
-// // Replace existing windows
-// let window = cx.windows()[0].downcast::<Workspace>().unwrap();
-// cx.update(|cx| {
-// open_paths(
-// &[PathBuf::from("/root/c"), PathBuf::from("/root/d")],
-// &app_state,
-// Some(window),
-// cx,
-// )
-// })
-// .await
-// .unwrap();
-// assert_eq!(cx.windows().len(), 2);
-// let workspace_1 = cx.windows()[0].downcast::<Workspace>().unwrap().root(cx);
-// workspace_1.update(cx, |workspace, cx| {
-// assert_eq!(
-// workspace
-// .worktrees(cx)
-// .map(|w| w.read(cx).abs_path())
-// .collect::<Vec<_>>(),
-// &[Path::new("/root/c").into(), Path::new("/root/d").into()]
-// );
-// assert!(workspace.left_dock().read(cx).is_open());
-// assert!(workspace.active_pane().is_focused(cx));
-// });
-// }
-
-// #[gpui::test]
-// async fn test_window_edit_state(executor: Arc<Deterministic>, cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// app_state
-// .fs
-// .as_fake()
-// .insert_tree("/root", json!({"a": "hey"}))
-// .await;
-
-// cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx))
-// .await
-// .unwrap();
-// assert_eq!(cx.windows().len(), 1);
-
-// // When opening the workspace, the window is not in a edited state.
-// let window = cx.windows()[0].downcast::<Workspace>().unwrap();
-// let workspace = window.root(cx);
-// let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
-// let editor = workspace.read_with(cx, |workspace, cx| {
-// workspace
-// .active_item(cx)
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap()
-// });
-// assert!(!window.is_edited(cx));
-
-// // Editing a buffer marks the window as edited.
-// editor.update(cx, |editor, cx| editor.insert("EDIT", cx));
-// assert!(window.is_edited(cx));
-
-// // Undoing the edit restores the window's edited state.
-// editor.update(cx, |editor, cx| editor.undo(&Default::default(), cx));
-// assert!(!window.is_edited(cx));
-
-// // Redoing the edit marks the window as edited again.
-// editor.update(cx, |editor, cx| editor.redo(&Default::default(), cx));
-// assert!(window.is_edited(cx));
-
-// // Closing the item restores the window's edited state.
-// let close = pane.update(cx, |pane, cx| {
-// drop(editor);
-// pane.close_active_item(&Default::default(), cx).unwrap()
-// });
-// executor.run_until_parked();
-
-// window.simulate_prompt_answer(1, cx);
-// close.await.unwrap();
-// assert!(!window.is_edited(cx));
-
-// // Opening the buffer again doesn't impact the window's edited state.
-// cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx))
-// .await
-// .unwrap();
-// let editor = workspace.read_with(cx, |workspace, cx| {
-// workspace
-// .active_item(cx)
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap()
-// });
-// assert!(!window.is_edited(cx));
-
-// // Editing the buffer marks the window as edited.
-// editor.update(cx, |editor, cx| editor.insert("EDIT", cx));
-// assert!(window.is_edited(cx));
-
-// // Ensure closing the window via the mouse gets preempted due to the
-// // buffer having unsaved changes.
-// assert!(!window.simulate_close(cx));
-// executor.run_until_parked();
-// assert_eq!(cx.windows().len(), 1);
-
-// // The window is successfully closed after the user dismisses the prompt.
-// window.simulate_prompt_answer(1, cx);
-// executor.run_until_parked();
-// assert_eq!(cx.windows().len(), 0);
-// }
-
-// #[gpui::test]
-// async fn test_new_empty_workspace(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// cx.update(|cx| {
-// open_new(&app_state, cx, |workspace, cx| {
-// Editor::new_file(workspace, &Default::default(), cx)
-// })
-// })
-// .await;
-
-// let window = cx
-// .windows()
-// .first()
-// .unwrap()
-// .downcast::<Workspace>()
-// .unwrap();
-// let workspace = window.root(cx);
-
-// let editor = workspace.update(cx, |workspace, cx| {
-// workspace
-// .active_item(cx)
-// .unwrap()
-// .downcast::<editor::Editor>()
-// .unwrap()
-// });
-
-// editor.update(cx, |editor, cx| {
-// assert!(editor.text(cx).is_empty());
-// assert!(!editor.is_dirty(cx));
-// });
-
-// let save_task = workspace.update(cx, |workspace, cx| {
-// workspace.save_active_item(SaveIntent::Save, cx)
-// });
-// app_state.fs.create_dir(Path::new("/root")).await.unwrap();
-// cx.foreground().run_until_parked();
-// cx.simulate_new_path_selection(|_| Some(PathBuf::from("/root/the-new-name")));
-// save_task.await.unwrap();
-// editor.read_with(cx, |editor, cx| {
-// assert!(!editor.is_dirty(cx));
-// assert_eq!(editor.title(cx), "the-new-name");
-// });
-// }
-
-// #[gpui::test]
-// async fn test_open_entry(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// app_state
-// .fs
-// .as_fake()
-// .insert_tree(
-// "/root",
-// json!({
-// "a": {
-// "file1": "contents 1",
-// "file2": "contents 2",
-// "file3": "contents 3",
-// },
-// }),
-// )
-// .await;
-
-// let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
-
-// let entries = cx.read(|cx| workspace.file_project_paths(cx));
-// let file1 = entries[0].clone();
-// let file2 = entries[1].clone();
-// let file3 = entries[2].clone();
-
-// // Open the first entry
-// let entry_1 = workspace
-// .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx))
-// .await
-// .unwrap();
-// cx.read(|cx| {
-// let pane = workspace.read(cx).active_pane().read(cx);
-// assert_eq!(
-// pane.active_item().unwrap().project_path(cx),
-// Some(file1.clone())
-// );
-// assert_eq!(pane.items_len(), 1);
-// });
-
-// // Open the second entry
-// workspace
-// .update(cx, |w, cx| w.open_path(file2.clone(), None, true, cx))
-// .await
-// .unwrap();
-// cx.read(|cx| {
-// let pane = workspace.read(cx).active_pane().read(cx);
-// assert_eq!(
-// pane.active_item().unwrap().project_path(cx),
-// Some(file2.clone())
-// );
-// assert_eq!(pane.items_len(), 2);
-// });
-
-// // Open the first entry again. The existing pane item is activated.
-// let entry_1b = workspace
-// .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx))
-// .await
-// .unwrap();
-// assert_eq!(entry_1.id(), entry_1b.id());
-
-// cx.read(|cx| {
-// let pane = workspace.read(cx).active_pane().read(cx);
-// assert_eq!(
-// pane.active_item().unwrap().project_path(cx),
-// Some(file1.clone())
-// );
-// assert_eq!(pane.items_len(), 2);
-// });
-
-// // Split the pane with the first entry, then open the second entry again.
-// workspace
-// .update(cx, |w, cx| {
-// w.split_and_clone(w.active_pane().clone(), SplitDirection::Right, cx);
-// w.open_path(file2.clone(), None, true, cx)
-// })
-// .await
-// .unwrap();
-
-// workspace.read_with(cx, |w, cx| {
-// assert_eq!(
-// w.active_pane()
-// .read(cx)
-// .active_item()
-// .unwrap()
-// .project_path(cx),
-// Some(file2.clone())
-// );
-// });
-
-// // Open the third entry twice concurrently. Only one pane item is added.
-// let (t1, t2) = workspace.update(cx, |w, cx| {
-// (
-// w.open_path(file3.clone(), None, true, cx),
-// w.open_path(file3.clone(), None, true, cx),
-// )
-// });
-// t1.await.unwrap();
-// t2.await.unwrap();
-// cx.read(|cx| {
-// let pane = workspace.read(cx).active_pane().read(cx);
-// assert_eq!(
-// pane.active_item().unwrap().project_path(cx),
-// Some(file3.clone())
-// );
-// let pane_entries = pane
-// .items()
-// .map(|i| i.project_path(cx).unwrap())
-// .collect::<Vec<_>>();
-// assert_eq!(pane_entries, &[file1, file2, file3]);
-// });
-// }
-
-// #[gpui::test]
-// async fn test_open_paths(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-
-// app_state
-// .fs
-// .as_fake()
-// .insert_tree(
-// "/",
-// json!({
-// "dir1": {
-// "a.txt": ""
-// },
-// "dir2": {
-// "b.txt": ""
-// },
-// "dir3": {
-// "c.txt": ""
-// },
-// "d.txt": ""
-// }),
-// )
-// .await;
-
-// cx.update(|cx| open_paths(&[PathBuf::from("/dir1/")], &app_state, None, cx))
-// .await
-// .unwrap();
-// assert_eq!(cx.windows().len(), 1);
-// let workspace = cx.windows()[0].downcast::<Workspace>().unwrap().root(cx);
-
-// #[track_caller]
-// fn assert_project_panel_selection(
-// workspace: &Workspace,
-// expected_worktree_path: &Path,
-// expected_entry_path: &Path,
-// cx: &AppContext,
-// ) {
-// let project_panel = [
-// workspace.left_dock().read(cx).panel::<ProjectPanel>(),
-// workspace.right_dock().read(cx).panel::<ProjectPanel>(),
-// workspace.bottom_dock().read(cx).panel::<ProjectPanel>(),
-// ]
-// .into_iter()
-// .find_map(std::convert::identity)
-// .expect("found no project panels")
-// .read(cx);
-// let (selected_worktree, selected_entry) = project_panel
-// .selected_entry(cx)
-// .expect("project panel should have a selected entry");
-// assert_eq!(
-// selected_worktree.abs_path().as_ref(),
-// expected_worktree_path,
-// "Unexpected project panel selected worktree path"
-// );
-// assert_eq!(
-// selected_entry.path.as_ref(),
-// expected_entry_path,
-// "Unexpected project panel selected entry path"
-// );
-// }
-
-// // Open a file within an existing worktree.
-// workspace
-// .update(cx, |view, cx| {
-// view.open_paths(vec!["/dir1/a.txt".into()], true, cx)
-// })
-// .await;
-// cx.read(|cx| {
-// let workspace = workspace.read(cx);
-// assert_project_panel_selection(workspace, Path::new("/dir1"), Path::new("a.txt"), cx);
-// assert_eq!(
-// workspace
-// .active_pane()
-// .read(cx)
-// .active_item()
-// .unwrap()
-// .as_any()
-// .downcast_ref::<Editor>()
-// .unwrap()
-// .read(cx)
-// .title(cx),
-// "a.txt"
-// );
-// });
-
-// // Open a file outside of any existing worktree.
-// workspace
-// .update(cx, |view, cx| {
-// view.open_paths(vec!["/dir2/b.txt".into()], true, cx)
-// })
-// .await;
-// cx.read(|cx| {
-// let workspace = workspace.read(cx);
-// assert_project_panel_selection(workspace, Path::new("/dir2/b.txt"), Path::new(""), cx);
-// let worktree_roots = workspace
-// .worktrees(cx)
-// .map(|w| w.read(cx).as_local().unwrap().abs_path().as_ref())
-// .collect::<HashSet<_>>();
-// assert_eq!(
-// worktree_roots,
-// vec!["/dir1", "/dir2/b.txt"]
-// .into_iter()
-// .map(Path::new)
-// .collect(),
-// );
-// assert_eq!(
-// workspace
-// .active_pane()
-// .read(cx)
-// .active_item()
-// .unwrap()
-// .as_any()
-// .downcast_ref::<Editor>()
-// .unwrap()
-// .read(cx)
-// .title(cx),
-// "b.txt"
-// );
-// });
-
-// // Ensure opening a directory and one of its children only adds one worktree.
-// workspace
-// .update(cx, |view, cx| {
-// view.open_paths(vec!["/dir3".into(), "/dir3/c.txt".into()], true, cx)
-// })
-// .await;
-// cx.read(|cx| {
-// let workspace = workspace.read(cx);
-// assert_project_panel_selection(workspace, Path::new("/dir3"), Path::new("c.txt"), cx);
-// let worktree_roots = workspace
-// .worktrees(cx)
-// .map(|w| w.read(cx).as_local().unwrap().abs_path().as_ref())
-// .collect::<HashSet<_>>();
-// assert_eq!(
-// worktree_roots,
-// vec!["/dir1", "/dir2/b.txt", "/dir3"]
-// .into_iter()
-// .map(Path::new)
-// .collect(),
-// );
-// assert_eq!(
-// workspace
-// .active_pane()
-// .read(cx)
-// .active_item()
-// .unwrap()
-// .as_any()
-// .downcast_ref::<Editor>()
-// .unwrap()
-// .read(cx)
-// .title(cx),
-// "c.txt"
-// );
-// });
-
-// // Ensure opening invisibly a file outside an existing worktree adds a new, invisible worktree.
-// workspace
-// .update(cx, |view, cx| {
-// view.open_paths(vec!["/d.txt".into()], false, cx)
-// })
-// .await;
-// cx.read(|cx| {
-// let workspace = workspace.read(cx);
-// assert_project_panel_selection(workspace, Path::new("/d.txt"), Path::new(""), cx);
-// let worktree_roots = workspace
-// .worktrees(cx)
-// .map(|w| w.read(cx).as_local().unwrap().abs_path().as_ref())
-// .collect::<HashSet<_>>();
-// assert_eq!(
-// worktree_roots,
-// vec!["/dir1", "/dir2/b.txt", "/dir3", "/d.txt"]
-// .into_iter()
-// .map(Path::new)
-// .collect(),
-// );
-
-// let visible_worktree_roots = workspace
-// .visible_worktrees(cx)
-// .map(|w| w.read(cx).as_local().unwrap().abs_path().as_ref())
-// .collect::<HashSet<_>>();
-// assert_eq!(
-// visible_worktree_roots,
-// vec!["/dir1", "/dir2/b.txt", "/dir3"]
-// .into_iter()
-// .map(Path::new)
-// .collect(),
-// );
-
-// assert_eq!(
-// workspace
-// .active_pane()
-// .read(cx)
-// .active_item()
-// .unwrap()
-// .as_any()
-// .downcast_ref::<Editor>()
-// .unwrap()
-// .read(cx)
-// .title(cx),
-// "d.txt"
-// );
-// });
-// }
-
-// #[gpui::test]
-// async fn test_opening_excluded_paths(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// cx.update(|cx| {
-// cx.update_global::<SettingsStore, _, _>(|store, cx| {
-// store.update_user_settings::<ProjectSettings>(cx, |project_settings| {
-// project_settings.file_scan_exclusions =
-// Some(vec!["excluded_dir".to_string(), "**/.git".to_string()]);
-// });
-// });
-// });
-// app_state
-// .fs
-// .as_fake()
-// .insert_tree(
-// "/root",
-// json!({
-// ".gitignore": "ignored_dir\n",
-// ".git": {
-// "HEAD": "ref: refs/heads/main",
-// },
-// "regular_dir": {
-// "file": "regular file contents",
-// },
-// "ignored_dir": {
-// "ignored_subdir": {
-// "file": "ignored subfile contents",
-// },
-// "file": "ignored file contents",
-// },
-// "excluded_dir": {
-// "file": "excluded file contents",
-// },
-// }),
-// )
-// .await;
-
-// let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
-
-// let initial_entries = cx.read(|cx| workspace.file_project_paths(cx));
-// let paths_to_open = [
-// Path::new("/root/excluded_dir/file").to_path_buf(),
-// Path::new("/root/.git/HEAD").to_path_buf(),
-// Path::new("/root/excluded_dir/ignored_subdir").to_path_buf(),
-// ];
-// let (opened_workspace, new_items) = cx
-// .update(|cx| workspace::open_paths(&paths_to_open, &app_state, None, cx))
-// .await
-// .unwrap();
-
-// assert_eq!(
-// opened_workspace.id(),
-// workspace.id(),
-// "Excluded files in subfolders of a workspace root should be opened in the workspace"
-// );
-// let mut opened_paths = cx.read(|cx| {
-// assert_eq!(
-// new_items.len(),
-// paths_to_open.len(),
-// "Expect to get the same number of opened items as submitted paths to open"
-// );
-// new_items
-// .iter()
-// .zip(paths_to_open.iter())
-// .map(|(i, path)| {
-// match i {
-// Some(Ok(i)) => {
-// Some(i.project_path(cx).map(|p| p.path.display().to_string()))
-// }
-// Some(Err(e)) => panic!("Excluded file {path:?} failed to open: {e:?}"),
-// None => None,
-// }
-// .flatten()
-// })
-// .collect::<Vec<_>>()
-// });
-// opened_paths.sort();
-// assert_eq!(
-// opened_paths,
-// vec![
-// None,
-// Some(".git/HEAD".to_string()),
-// Some("excluded_dir/file".to_string()),
-// ],
-// "Excluded files should get opened, excluded dir should not get opened"
-// );
-
-// let entries = cx.read(|cx| workspace.file_project_paths(cx));
-// assert_eq!(
-// initial_entries, entries,
-// "Workspace entries should not change after opening excluded files and directories paths"
-// );
-
-// cx.read(|cx| {
-// let pane = workspace.read(cx).active_pane().read(cx);
-// let mut opened_buffer_paths = pane
-// .items()
-// .map(|i| {
-// i.project_path(cx)
-// .expect("all excluded files that got open should have a path")
-// .path
-// .display()
-// .to_string()
-// })
-// .collect::<Vec<_>>();
-// opened_buffer_paths.sort();
-// assert_eq!(
-// opened_buffer_paths,
-// vec![".git/HEAD".to_string(), "excluded_dir/file".to_string()],
-// "Despite not being present in the worktrees, buffers for excluded files are opened and added to the pane"
-// );
-// });
-// }
-
-// #[gpui::test]
-// async fn test_save_conflicting_item(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// app_state
-// .fs
-// .as_fake()
-// .insert_tree("/root", json!({ "a.txt": "" }))
-// .await;
-
-// let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
-
-// // Open a file within an existing worktree.
-// workspace
-// .update(cx, |view, cx| {
-// view.open_paths(vec![PathBuf::from("/root/a.txt")], true, cx)
-// })
-// .await;
-// let editor = cx.read(|cx| {
-// let pane = workspace.read(cx).active_pane().read(cx);
-// let item = pane.active_item().unwrap();
-// item.downcast::<Editor>().unwrap()
-// });
-
-// editor.update(cx, |editor, cx| editor.handle_input("x", cx));
-// app_state
-// .fs
-// .as_fake()
-// .insert_file("/root/a.txt", "changed".to_string())
-// .await;
-// editor
-// .condition(cx, |editor, cx| editor.has_conflict(cx))
-// .await;
-// cx.read(|cx| assert!(editor.is_dirty(cx)));
-
-// let save_task = workspace.update(cx, |workspace, cx| {
-// workspace.save_active_item(SaveIntent::Save, cx)
-// });
-// cx.foreground().run_until_parked();
-// window.simulate_prompt_answer(0, cx);
-// save_task.await.unwrap();
-// editor.read_with(cx, |editor, cx| {
-// assert!(!editor.is_dirty(cx));
-// assert!(!editor.has_conflict(cx));
-// });
-// }
-
-// #[gpui::test]
-// async fn test_open_and_save_new_file(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// app_state.fs.create_dir(Path::new("/root")).await.unwrap();
-
-// let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
-// project.update(cx, |project, _| project.languages().add(rust_lang()));
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
-// let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap());
-
-// // Create a new untitled buffer
-// cx.dispatch_action(window.into(), NewFile);
-// let editor = workspace.read_with(cx, |workspace, cx| {
-// workspace
-// .active_item(cx)
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap()
-// });
-
-// editor.update(cx, |editor, cx| {
-// assert!(!editor.is_dirty(cx));
-// assert_eq!(editor.title(cx), "untitled");
-// assert!(Arc::ptr_eq(
-// &editor.language_at(0, cx).unwrap(),
-// &languages::PLAIN_TEXT
-// ));
-// editor.handle_input("hi", cx);
-// assert!(editor.is_dirty(cx));
-// });
-
-// // Save the buffer. This prompts for a filename.
-// let save_task = workspace.update(cx, |workspace, cx| {
-// workspace.save_active_item(SaveIntent::Save, cx)
-// });
-// cx.foreground().run_until_parked();
-// cx.simulate_new_path_selection(|parent_dir| {
-// assert_eq!(parent_dir, Path::new("/root"));
-// Some(parent_dir.join("the-new-name.rs"))
-// });
-// cx.read(|cx| {
-// assert!(editor.is_dirty(cx));
-// assert_eq!(editor.read(cx).title(cx), "untitled");
-// });
-
-// // When the save completes, the buffer's title is updated and the language is assigned based
-// // on the path.
-// save_task.await.unwrap();
-// editor.read_with(cx, |editor, cx| {
-// assert!(!editor.is_dirty(cx));
-// assert_eq!(editor.title(cx), "the-new-name.rs");
-// assert_eq!(editor.language_at(0, cx).unwrap().name().as_ref(), "Rust");
-// });
-
-// // Edit the file and save it again. This time, there is no filename prompt.
-// editor.update(cx, |editor, cx| {
-// editor.handle_input(" there", cx);
-// assert!(editor.is_dirty(cx));
-// });
-// let save_task = workspace.update(cx, |workspace, cx| {
-// workspace.save_active_item(SaveIntent::Save, cx)
-// });
-// save_task.await.unwrap();
-// assert!(!cx.did_prompt_for_new_path());
-// editor.read_with(cx, |editor, cx| {
-// assert!(!editor.is_dirty(cx));
-// assert_eq!(editor.title(cx), "the-new-name.rs")
-// });
-
-// // Open the same newly-created file in another pane item. The new editor should reuse
-// // the same buffer.
-// cx.dispatch_action(window.into(), NewFile);
-// workspace
-// .update(cx, |workspace, cx| {
-// workspace.split_and_clone(
-// workspace.active_pane().clone(),
-// SplitDirection::Right,
-// cx,
-// );
-// workspace.open_path((worktree.read(cx).id(), "the-new-name.rs"), None, true, cx)
-// })
-// .await
-// .unwrap();
-// let editor2 = workspace.update(cx, |workspace, cx| {
-// workspace
-// .active_item(cx)
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap()
-// });
-// cx.read(|cx| {
-// assert_eq!(
-// editor2.read(cx).buffer().read(cx).as_singleton().unwrap(),
-// editor.read(cx).buffer().read(cx).as_singleton().unwrap()
-// );
-// })
-// }
-
-// #[gpui::test]
-// async fn test_setting_language_when_saving_as_single_file_worktree(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// app_state.fs.create_dir(Path::new("/root")).await.unwrap();
-
-// let project = Project::test(app_state.fs.clone(), [], cx).await;
-// project.update(cx, |project, _| project.languages().add(rust_lang()));
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
-
-// // Create a new untitled buffer
-// cx.dispatch_action(window.into(), NewFile);
-// let editor = workspace.read_with(cx, |workspace, cx| {
-// workspace
-// .active_item(cx)
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap()
-// });
-
-// editor.update(cx, |editor, cx| {
-// assert!(Arc::ptr_eq(
-// &editor.language_at(0, cx).unwrap(),
-// &languages::PLAIN_TEXT
-// ));
-// editor.handle_input("hi", cx);
-// assert!(editor.is_dirty(cx));
-// });
-
-// // Save the buffer. This prompts for a filename.
-// let save_task = workspace.update(cx, |workspace, cx| {
-// workspace.save_active_item(SaveIntent::Save, cx)
-// });
-// cx.foreground().run_until_parked();
-// cx.simulate_new_path_selection(|_| Some(PathBuf::from("/root/the-new-name.rs")));
-// save_task.await.unwrap();
-// // The buffer is not dirty anymore and the language is assigned based on the path.
-// editor.read_with(cx, |editor, cx| {
-// assert!(!editor.is_dirty(cx));
-// assert_eq!(editor.language_at(0, cx).unwrap().name().as_ref(), "Rust")
-// });
-// }
-
-// #[gpui::test]
-// async fn test_pane_actions(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// app_state
-// .fs
-// .as_fake()
-// .insert_tree(
-// "/root",
-// json!({
-// "a": {
-// "file1": "contents 1",
-// "file2": "contents 2",
-// "file3": "contents 3",
-// },
-// }),
-// )
-// .await;
-
-// let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
-// let window = cx.add_window(|cx| Workspace::test_new(project, cx));
-// let workspace = window.root(cx);
-
-// let entries = cx.read(|cx| workspace.file_project_paths(cx));
-// let file1 = entries[0].clone();
-
-// let pane_1 = cx.read(|cx| workspace.read(cx).active_pane().clone());
-
-// workspace
-// .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx))
-// .await
-// .unwrap();
-
-// let (editor_1, buffer) = pane_1.update(cx, |pane_1, cx| {
-// let editor = pane_1.active_item().unwrap().downcast::<Editor>().unwrap();
-// assert_eq!(editor.project_path(cx), Some(file1.clone()));
-// let buffer = editor.update(cx, |editor, cx| {
-// editor.insert("dirt", cx);
-// editor.buffer().downgrade()
-// });
-// (editor.downgrade(), buffer)
-// });
-
-// cx.dispatch_action(window.into(), pane::SplitRight);
-// let editor_2 = cx.update(|cx| {
-// let pane_2 = workspace.read(cx).active_pane().clone();
-// assert_ne!(pane_1, pane_2);
-
-// let pane2_item = pane_2.read(cx).active_item().unwrap();
-// assert_eq!(pane2_item.project_path(cx), Some(file1.clone()));
-
-// pane2_item.downcast::<Editor>().unwrap().downgrade()
-// });
-// cx.dispatch_action(
-// window.into(),
-// workspace::CloseActiveItem { save_intent: None },
-// );
-
-// cx.foreground().run_until_parked();
-// workspace.read_with(cx, |workspace, _| {
-// assert_eq!(workspace.panes().len(), 1);
-// assert_eq!(workspace.active_pane(), &pane_1);
-// });
-
-// cx.dispatch_action(
-// window.into(),
-// workspace::CloseActiveItem { save_intent: None },
-// );
-// cx.foreground().run_until_parked();
-// window.simulate_prompt_answer(1, cx);
-// cx.foreground().run_until_parked();
-
-// workspace.read_with(cx, |workspace, cx| {
-// assert_eq!(workspace.panes().len(), 1);
-// assert!(workspace.active_item(cx).is_none());
-// });
-
-// cx.assert_dropped(editor_1);
-// cx.assert_dropped(editor_2);
-// cx.assert_dropped(buffer);
-// }
-
-// #[gpui::test]
-// async fn test_navigation(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// app_state
-// .fs
-// .as_fake()
-// .insert_tree(
-// "/root",
-// json!({
-// "a": {
-// "file1": "contents 1\n".repeat(20),
-// "file2": "contents 2\n".repeat(20),
-// "file3": "contents 3\n".repeat(20),
-// },
-// }),
-// )
-// .await;
-
-// let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
-// let workspace = cx
-// .add_window(|cx| Workspace::test_new(project.clone(), cx))
-// .root(cx);
-// let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
-
-// let entries = cx.read(|cx| workspace.file_project_paths(cx));
-// let file1 = entries[0].clone();
-// let file2 = entries[1].clone();
-// let file3 = entries[2].clone();
-
-// let editor1 = workspace
-// .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx))
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-// editor1.update(cx, |editor, cx| {
-// editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
-// s.select_display_ranges([DisplayPoint::new(10, 0)..DisplayPoint::new(10, 0)])
-// });
-// });
-// let editor2 = workspace
-// .update(cx, |w, cx| w.open_path(file2.clone(), None, true, cx))
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-// let editor3 = workspace
-// .update(cx, |w, cx| w.open_path(file3.clone(), None, true, cx))
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-
-// editor3
-// .update(cx, |editor, cx| {
-// editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
-// s.select_display_ranges([DisplayPoint::new(12, 0)..DisplayPoint::new(12, 0)])
-// });
-// editor.newline(&Default::default(), cx);
-// editor.newline(&Default::default(), cx);
-// editor.move_down(&Default::default(), cx);
-// editor.move_down(&Default::default(), cx);
-// editor.save(project.clone(), cx)
-// })
-// .await
-// .unwrap();
-// editor3.update(cx, |editor, cx| {
-// editor.set_scroll_position(vec2f(0., 12.5), cx)
-// });
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file3.clone(), DisplayPoint::new(16, 0), 12.5)
-// );
-
-// workspace
-// .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file3.clone(), DisplayPoint::new(0, 0), 0.)
-// );
-
-// workspace
-// .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file2.clone(), DisplayPoint::new(0, 0), 0.)
-// );
-
-// workspace
-// .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file1.clone(), DisplayPoint::new(10, 0), 0.)
-// );
-
-// workspace
-// .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file1.clone(), DisplayPoint::new(0, 0), 0.)
-// );
-
-// // Go back one more time and ensure we don't navigate past the first item in the history.
-// workspace
-// .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file1.clone(), DisplayPoint::new(0, 0), 0.)
-// );
-
-// workspace
-// .update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file1.clone(), DisplayPoint::new(10, 0), 0.)
-// );
-
-// workspace
-// .update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file2.clone(), DisplayPoint::new(0, 0), 0.)
-// );
-
-// // Go forward to an item that has been closed, ensuring it gets re-opened at the same
-// // location.
-// pane.update(cx, |pane, cx| {
-// let editor3_id = editor3.id();
-// drop(editor3);
-// pane.close_item_by_id(editor3_id, SaveIntent::Close, cx)
-// })
-// .await
-// .unwrap();
-// workspace
-// .update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file3.clone(), DisplayPoint::new(0, 0), 0.)
-// );
-
-// workspace
-// .update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file3.clone(), DisplayPoint::new(16, 0), 12.5)
-// );
-
-// workspace
-// .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file3.clone(), DisplayPoint::new(0, 0), 0.)
-// );
-
-// // Go back to an item that has been closed and removed from disk, ensuring it gets skipped.
-// pane.update(cx, |pane, cx| {
-// let editor2_id = editor2.id();
-// drop(editor2);
-// pane.close_item_by_id(editor2_id, SaveIntent::Close, cx)
-// })
-// .await
-// .unwrap();
-// app_state
-// .fs
-// .remove_file(Path::new("/root/a/file2"), Default::default())
-// .await
-// .unwrap();
-// cx.foreground().run_until_parked();
-
-// workspace
-// .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file1.clone(), DisplayPoint::new(10, 0), 0.)
-// );
-// workspace
-// .update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file3.clone(), DisplayPoint::new(0, 0), 0.)
-// );
-
-// // Modify file to collapse multiple nav history entries into the same location.
-// // Ensure we don't visit the same location twice when navigating.
-// editor1.update(cx, |editor, cx| {
-// editor.change_selections(None, cx, |s| {
-// s.select_display_ranges([DisplayPoint::new(15, 0)..DisplayPoint::new(15, 0)])
-// })
-// });
-
-// for _ in 0..5 {
-// editor1.update(cx, |editor, cx| {
-// editor.change_selections(None, cx, |s| {
-// s.select_display_ranges([DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)])
-// });
-// });
-// editor1.update(cx, |editor, cx| {
-// editor.change_selections(None, cx, |s| {
-// s.select_display_ranges([DisplayPoint::new(13, 0)..DisplayPoint::new(13, 0)])
-// })
-// });
-// }
-
-// editor1.update(cx, |editor, cx| {
-// editor.transact(cx, |editor, cx| {
-// editor.change_selections(None, cx, |s| {
-// s.select_display_ranges([DisplayPoint::new(2, 0)..DisplayPoint::new(14, 0)])
-// });
-// editor.insert("", cx);
-// })
-// });
-
-// editor1.update(cx, |editor, cx| {
-// editor.change_selections(None, cx, |s| {
-// s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)])
-// })
-// });
-// workspace
-// .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file1.clone(), DisplayPoint::new(2, 0), 0.)
-// );
-// workspace
-// .update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
-// .await
-// .unwrap();
-// assert_eq!(
-// active_location(&workspace, cx),
-// (file1.clone(), DisplayPoint::new(3, 0), 0.)
-// );
-
-// fn active_location(
-// workspace: &ViewHandle<Workspace>,
-// cx: &mut TestAppContext,
-// ) -> (ProjectPath, DisplayPoint, f32) {
-// workspace.update(cx, |workspace, cx| {
-// let item = workspace.active_item(cx).unwrap();
-// let editor = item.downcast::<Editor>().unwrap();
-// let (selections, scroll_position) = editor.update(cx, |editor, cx| {
-// (
-// editor.selections.display_ranges(cx),
-// editor.scroll_position(cx),
-// )
-// });
-// (
-// item.project_path(cx).unwrap(),
-// selections[0].start,
-// scroll_position.y(),
-// )
-// })
-// }
-// }
-
-// #[gpui::test]
-// async fn test_reopening_closed_items(cx: &mut TestAppContext) {
-// let app_state = init_test(cx);
-// app_state
-// .fs
-// .as_fake()
-// .insert_tree(
-// "/root",
-// json!({
-// "a": {
-// "file1": "",
-// "file2": "",
-// "file3": "",
-// "file4": "",
-// },
-// }),
-// )
-// .await;
-
-// let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
-// let workspace = cx
-// .add_window(|cx| Workspace::test_new(project, cx))
-// .root(cx);
-// let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
-
-// let entries = cx.read(|cx| workspace.file_project_paths(cx));
-// let file1 = entries[0].clone();
-// let file2 = entries[1].clone();
-// let file3 = entries[2].clone();
-// let file4 = entries[3].clone();
-
-// let file1_item_id = workspace
-// .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx))
-// .await
-// .unwrap()
-// .id();
-// let file2_item_id = workspace
-// .update(cx, |w, cx| w.open_path(file2.clone(), None, true, cx))
-// .await
-// .unwrap()
-// .id();
-// let file3_item_id = workspace
-// .update(cx, |w, cx| w.open_path(file3.clone(), None, true, cx))
-// .await
-// .unwrap()
-// .id();
-// let file4_item_id = workspace
-// .update(cx, |w, cx| w.open_path(file4.clone(), None, true, cx))
-// .await
-// .unwrap()
-// .id();
-// assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
-
-// // Close all the pane items in some arbitrary order.
-// pane.update(cx, |pane, cx| {
-// pane.close_item_by_id(file1_item_id, SaveIntent::Close, cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
-
-// pane.update(cx, |pane, cx| {
-// pane.close_item_by_id(file4_item_id, SaveIntent::Close, cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
-
-// pane.update(cx, |pane, cx| {
-// pane.close_item_by_id(file2_item_id, SaveIntent::Close, cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
-
-// pane.update(cx, |pane, cx| {
-// pane.close_item_by_id(file3_item_id, SaveIntent::Close, cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), None);
-
-// // Reopen all the closed items, ensuring they are reopened in the same order
-// // in which they were closed.
-// workspace
-// .update(cx, Workspace::reopen_closed_item)
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
-
-// workspace
-// .update(cx, Workspace::reopen_closed_item)
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file2.clone()));
-
-// workspace
-// .update(cx, Workspace::reopen_closed_item)
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
-
-// workspace
-// .update(cx, Workspace::reopen_closed_item)
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
-
-// // Reopening past the last closed item is a no-op.
-// workspace
-// .update(cx, Workspace::reopen_closed_item)
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
-
-// // Reopening closed items doesn't interfere with navigation history.
-// workspace
-// .update(cx, |workspace, cx| {
-// workspace.go_back(workspace.active_pane().downgrade(), cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
-
-// workspace
-// .update(cx, |workspace, cx| {
-// workspace.go_back(workspace.active_pane().downgrade(), cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file2.clone()));
-
-// workspace
-// .update(cx, |workspace, cx| {
-// workspace.go_back(workspace.active_pane().downgrade(), cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
-
-// workspace
-// .update(cx, |workspace, cx| {
-// workspace.go_back(workspace.active_pane().downgrade(), cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
-
-// workspace
-// .update(cx, |workspace, cx| {
-// workspace.go_back(workspace.active_pane().downgrade(), cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
-
-// workspace
-// .update(cx, |workspace, cx| {
-// workspace.go_back(workspace.active_pane().downgrade(), cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file2.clone()));
-
-// workspace
-// .update(cx, |workspace, cx| {
-// workspace.go_back(workspace.active_pane().downgrade(), cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
-
-// workspace
-// .update(cx, |workspace, cx| {
-// workspace.go_back(workspace.active_pane().downgrade(), cx)
-// })
-// .await
-// .unwrap();
-// assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
-
-// fn active_path(
-// workspace: &ViewHandle<Workspace>,
-// cx: &TestAppContext,
-// ) -> Option<ProjectPath> {
-// workspace.read_with(cx, |workspace, cx| {
-// let item = workspace.active_item(cx)?;
-// item.project_path(cx)
-// })
-// }
-// }
-
-// #[gpui::test]
-// async fn test_base_keymap(cx: &mut gpui::TestAppContext) {
-// struct TestView;
-
-// impl Entity for TestView {
-// type Event = ();
-// }
-
-// impl View for TestView {
-// fn ui_name() -> &'static str {
-// "TestView"
-// }
-
-// fn render(&mut self, _: &mut ViewContext<Self>) -> AnyElement<Self> {
-// Empty::new().into_any()
-// }
-// }
-
-// let executor = cx.background();
-// let fs = FakeFs::new(executor.clone());
-
-// actions!(test, [A, B]);
-// // From the Atom keymap
-// actions!(workspace, [ActivatePreviousPane]);
-// // From the JetBrains keymap
-// actions!(pane, [ActivatePrevItem]);
-
-// fs.save(
-// "/settings.json".as_ref(),
-// &r#"
-// {
-// "base_keymap": "Atom"
-// }
-// "#
-// .into(),
-// Default::default(),
-// )
-// .await
-// .unwrap();
-
-// fs.save(
-// "/keymap.json".as_ref(),
-// &r#"
-// [
-// {
-// "bindings": {
-// "backspace": "test::A"
-// }
-// }
-// ]
-// "#
-// .into(),
-// Default::default(),
-// )
-// .await
-// .unwrap();
-
-// cx.update(|cx| {
-// cx.set_global(SettingsStore::test(cx));
-// theme::init(Assets, cx);
-// welcome::init(cx);
-
-// cx.add_global_action(|_: &A, _cx| {});
-// cx.add_global_action(|_: &B, _cx| {});
-// cx.add_global_action(|_: &ActivatePreviousPane, _cx| {});
-// cx.add_global_action(|_: &ActivatePrevItem, _cx| {});
-
-// let settings_rx = watch_config_file(
-// executor.clone(),
-// fs.clone(),
-// PathBuf::from("/settings.json"),
-// );
-// let keymap_rx =
-// watch_config_file(executor.clone(), fs.clone(), PathBuf::from("/keymap.json"));
-
-// handle_keymap_file_changes(keymap_rx, cx);
-// handle_settings_file_changes(settings_rx, cx);
-// });
-
-// cx.foreground().run_until_parked();
-
-// let window = cx.add_window(|_| TestView);
-
-// // Test loading the keymap base at all
-// assert_key_bindings_for(
-// window.into(),
-// cx,
-// vec![("backspace", &A), ("k", &ActivatePreviousPane)],
-// line!(),
-// );
-
-// // Test modifying the users keymap, while retaining the base keymap
-// fs.save(
-// "/keymap.json".as_ref(),
-// &r#"
-// [
-// {
-// "bindings": {
-// "backspace": "test::B"
-// }
-// }
-// ]
-// "#
-// .into(),
-// Default::default(),
-// )
-// .await
-// .unwrap();
-
-// cx.foreground().run_until_parked();
-
-// assert_key_bindings_for(
-// window.into(),
-// cx,
-// vec![("backspace", &B), ("k", &ActivatePreviousPane)],
-// line!(),
-// );
-
-// // Test modifying the base, while retaining the users keymap
-// fs.save(
-// "/settings.json".as_ref(),
-// &r#"
-// {
-// "base_keymap": "JetBrains"
-// }
-// "#
-// .into(),
-// Default::default(),
-// )
-// .await
-// .unwrap();
-
-// cx.foreground().run_until_parked();
-
-// assert_key_bindings_for(
-// window.into(),
-// cx,
-// vec![("backspace", &B), ("[", &ActivatePrevItem)],
-// line!(),
-// );
-
-// #[track_caller]
-// fn assert_key_bindings_for<'a>(
-// window: AnyWindowHandle,
-// cx: &TestAppContext,
-// actions: Vec<(&'static str, &'a dyn Action)>,
-// line: u32,
-// ) {
-// for (key, action) in actions {
-// // assert that...
-// assert!(
-// cx.available_actions(window, 0)
-// .into_iter()
-// .any(|(_, bound_action, b)| {
-// // action names match...
-// bound_action.name() == action.name()
-// && bound_action.namespace() == action.namespace()
-// // and key strokes contain the given key
-// && b.iter()
-// .any(|binding| binding.keystrokes().iter().any(|k| k.key == key))
-// }),
-// "On {} Failed to find {} with key binding {}",
-// line,
-// action.name(),
-// key
-// );
-// }
-// }
-// }
-
-// #[gpui::test]
-// async fn test_disabled_keymap_binding(cx: &mut gpui::TestAppContext) {
-// struct TestView;
-
-// impl Entity for TestView {
-// type Event = ();
-// }
-
-// impl View for TestView {
-// fn ui_name() -> &'static str {
-// "TestView"
-// }
-
-// fn render(&mut self, _: &mut ViewContext<Self>) -> AnyElement<Self> {
-// Empty::new().into_any()
-// }
-// }
-
-// let executor = cx.background();
-// let fs = FakeFs::new(executor.clone());
-
-// actions!(test, [A, B]);
-// // From the Atom keymap
-// actions!(workspace, [ActivatePreviousPane]);
-// // From the JetBrains keymap
-// actions!(pane, [ActivatePrevItem]);
-
-// fs.save(
-// "/settings.json".as_ref(),
-// &r#"
-// {
-// "base_keymap": "Atom"
-// }
-// "#
-// .into(),
-// Default::default(),
-// )
-// .await
-// .unwrap();
-
-// fs.save(
-// "/keymap.json".as_ref(),
-// &r#"
-// [
-// {
-// "bindings": {
-// "backspace": "test::A"
-// }
-// }
-// ]
-// "#
-// .into(),
-// Default::default(),
-// )
-// .await
-// .unwrap();
-
-// cx.update(|cx| {
-// cx.set_global(SettingsStore::test(cx));
-// theme::init(Assets, cx);
-// welcome::init(cx);
-
-// cx.add_global_action(|_: &A, _cx| {});
-// cx.add_global_action(|_: &B, _cx| {});
-// cx.add_global_action(|_: &ActivatePreviousPane, _cx| {});
-// cx.add_global_action(|_: &ActivatePrevItem, _cx| {});
-
-// let settings_rx = watch_config_file(
-// executor.clone(),
-// fs.clone(),
-// PathBuf::from("/settings.json"),
-// );
-// let keymap_rx =
-// watch_config_file(executor.clone(), fs.clone(), PathBuf::from("/keymap.json"));
-
-// handle_keymap_file_changes(keymap_rx, cx);
-// handle_settings_file_changes(settings_rx, cx);
-// });
-
-// cx.foreground().run_until_parked();
-
-// let window = cx.add_window(|_| TestView);
-
-// // Test loading the keymap base at all
-// assert_key_bindings_for(
-// window.into(),
-// cx,
-// vec![("backspace", &A), ("k", &ActivatePreviousPane)],
-// line!(),
-// );
-
-// // Test disabling the key binding for the base keymap
-// fs.save(
-// "/keymap.json".as_ref(),
-// &r#"
-// [
-// {
-// "bindings": {
-// "backspace": null
-// }
-// }
-// ]
-// "#
-// .into(),
-// Default::default(),
-// )
-// .await
-// .unwrap();
-
-// cx.foreground().run_until_parked();
-
-// assert_key_bindings_for(
-// window.into(),
-// cx,
-// vec![("k", &ActivatePreviousPane)],
-// line!(),
-// );
-
-// // Test modifying the base, while retaining the users keymap
-// fs.save(
-// "/settings.json".as_ref(),
-// &r#"
-// {
-// "base_keymap": "JetBrains"
-// }
-// "#
-// .into(),
-// Default::default(),
-// )
-// .await
-// .unwrap();
-
-// cx.foreground().run_until_parked();
-
-// assert_key_bindings_for(window.into(), cx, vec![("[", &ActivatePrevItem)], line!());
-
-// #[track_caller]
-// fn assert_key_bindings_for<'a>(
-// window: AnyWindowHandle,
-// cx: &TestAppContext,
-// actions: Vec<(&'static str, &'a dyn Action)>,
-// line: u32,
-// ) {
-// for (key, action) in actions {
-// // assert that...
-// assert!(
-// cx.available_actions(window, 0)
-// .into_iter()
-// .any(|(_, bound_action, b)| {
-// // action names match...
-// bound_action.name() == action.name()
-// && bound_action.namespace() == action.namespace()
-// // and key strokes contain the given key
-// && b.iter()
-// .any(|binding| binding.keystrokes().iter().any(|k| k.key == key))
-// }),
-// "On {} Failed to find {} with key binding {}",
-// line,
-// action.name(),
-// key
-// );
-// }
-// }
-// }
-
-// #[gpui::test]
-// fn test_bundled_settings_and_themes(cx: &mut AppContext) {
-// cx.platform()
-// .fonts()
-// .add_fonts(&[
-// Assets
-// .load("fonts/zed-sans/zed-sans-extended.ttf")
-// .unwrap()
-// .to_vec()
-// .into(),
-// Assets
-// .load("fonts/zed-mono/zed-mono-extended.ttf")
-// .unwrap()
-// .to_vec()
-// .into(),
-// Assets
-// .load("fonts/plex/IBMPlexSans-Regular.ttf")
-// .unwrap()
-// .to_vec()
-// .into(),
-// ])
-// .unwrap();
-// let themes = ThemeRegistry::new(Assets, cx.font_cache().clone());
-// let mut settings = SettingsStore::default();
-// settings
-// .set_default_settings(&settings::default_settings(), cx)
-// .unwrap();
-// cx.set_global(settings);
-// theme::init(Assets, cx);
-
-// let mut has_default_theme = false;
-// for theme_name in themes.list(false).map(|meta| meta.name) {
-// let theme = themes.get(&theme_name).unwrap();
-// assert_eq!(theme.meta.name, theme_name);
-// if theme.meta.name == settings::get::<ThemeSettings>(cx).theme.meta.name {
-// has_default_theme = true;
-// }
-// }
-// assert!(has_default_theme);
-// }
-
-// #[gpui::test]
-// fn test_bundled_languages(cx: &mut AppContext) {
-// cx.set_global(SettingsStore::test(cx));
-// let mut languages = LanguageRegistry::test();
-// languages.set_executor(cx.background().clone());
-// let languages = Arc::new(languages);
-// let node_runtime = node_runtime::FakeNodeRuntime::new();
-// languages::init(languages.clone(), node_runtime, cx);
-// for name in languages.language_names() {
-// languages.language_for_name(&name);
-// }
-// cx.foreground().run_until_parked();
-// }
-
-// fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
-// cx.foreground().forbid_parking();
-// cx.update(|cx| {
-// let mut app_state = AppState::test(cx);
-// let state = Arc::get_mut(&mut app_state).unwrap();
-// state.initialize_workspace = initialize_workspace;
-// state.build_window_options = build_window_options;
-// theme::init((), cx);
-// audio::init((), cx);
-// channel::init(&app_state.client, app_state.user_store.clone(), cx);
-// call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
-// notifications::init(app_state.client.clone(), app_state.user_store.clone(), cx);
-// workspace::init(app_state.clone(), cx);
-// Project::init_settings(cx);
-// language::init(cx);
-// editor::init(cx);
-// project_panel::init_settings(cx);
-// collab_ui::init(&app_state, cx);
-// pane::init(cx);
-// project_panel::init((), cx);
-// terminal_view::init(cx);
-// assistant::init(cx);
-// app_state
-// })
-// }
-
-// fn rust_lang() -> Arc<language::Language> {
-// Arc::new(language::Language::new(
-// language::LanguageConfig {
-// name: "Rust".into(),
-// path_suffixes: vec!["rs".to_string()],
-// ..Default::default()
-// },
-// Some(tree_sitter_rust::language()),
-// ))
-// }
-// }
@@ -17,6 +17,6 @@
## Testing collab locally
1. Run `foreman start` from the root of the repo.
-1. In another terminal run `script/zed-local -2`.
+1. In another terminal run `script/zed-local`.
1. Two copies of Zed will open. Add yourself as a contact in the one that is not you.
1. Start a collaboration session as normal with any open project.
@@ -17,6 +17,6 @@
## Testing collab locally
1. Run `foreman start` from the root of the repo.
-1. In another terminal run `script/zed-local -2`.
+1. In another terminal run `script/zed-local`.
1. Two copies of Zed will open. Add yourself as a contact in the one that is not you.
1. Start a collaboration session as normal with any open project.
@@ -27,11 +27,10 @@ Options:
-o Open the resulting DMG or the app itself in local mode.
-f Overwrite the local app bundle if it exists.
-h Display this help and exit.
- -2 Build zed 2 instead of zed 1.
"
}
-while getopts 'dlfoh2' flag
+while getopts 'dlfoh' flag
do
case "${flag}" in
o) open_result=true;;
@@ -50,10 +49,6 @@ do
target_dir="debug"
;;
f) overwrite_local_app=true;;
- 2)
- zed_crate="zed2"
- binary_name="Zed2"
- ;;
h)
help_info
exit 0
@@ -152,12 +147,7 @@ if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTAR
# sequence of codesign commands modeled after this example: https://developer.apple.com/forums/thread/701514
/usr/bin/codesign --deep --force --timestamp --sign "Zed Industries, Inc." "${app_path}/Contents/Frameworks/WebRTC.framework" -v
-
- # todo!(restore cli to zed2)
- if [[ "$zed_crate" == "zed" ]]; then
- /usr/bin/codesign --deep --force --timestamp --options runtime --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/cli" -v
- fi
-
+ /usr/bin/codesign --deep --force --timestamp --options runtime --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/cli" -v
/usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/${zed_crate}/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/${zed_crate}" -v
/usr/bin/codesign --force --timestamp --options runtime --entitlements crates/${zed_crate}/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}" -v
@@ -11,7 +11,7 @@ graph_file=target/crate-graph.html
cargo depgraph \
--workspace-only \
--offline \
- --root=zed2,cli,collab2 \
+ --root=zed,cli,collab2 \
--dedup-transitive-deps \
| dot -Tsvg > $graph_file
@@ -1,27 +0,0 @@
-import os
-from pathlib import Path
-
-THIS_SCRIPT_PATH: Path = Path(__file__)
-CRATES_DIR: Path = THIS_SCRIPT_PATH.parent.parent / "crates"
-
-zed_1_crate_count: int = 0
-zed_2_crate_count: int = 0
-
-for child in os.listdir(CRATES_DIR):
- child_path: str = os.path.join(CRATES_DIR, child)
-
- if not os.path.isdir(child_path):
- continue
-
- if child.endswith("2"):
- zed_2_crate_count += 1
- else:
- zed_1_crate_count += 1
-
-print(f"crates ported: {zed_2_crate_count}")
-print(f"crates in total: {zed_1_crate_count}")
-
-percent_complete: float = (zed_2_crate_count / zed_1_crate_count) * 100
-percent_complete_rounded: float = round(percent_complete, 2)
-
-print(f"progress: {percent_complete_rounded}%")
@@ -4,7 +4,6 @@ const { spawn, execFileSync } = require("child_process");
const RESOLUTION_REGEX = /(\d+) x (\d+)/;
const DIGIT_FLAG_REGEX = /^--?(\d+)$/;
-const ZED_2_MODE = "--zed2";
const RELEASE_MODE = "--release";
const args = process.argv.slice(2);
@@ -16,7 +15,6 @@ if (digitMatch) {
instanceCount = parseInt(digitMatch[1]);
args.shift();
}
-const isZed2 = args.some((arg) => arg === ZED_2_MODE);
const isReleaseMode = args.some((arg) => arg === RELEASE_MODE);
if (instanceCount > 4) {
throw new Error("Cannot spawn more than 4 instances");
@@ -71,17 +69,11 @@ const buildArgs = (() => {
buildArgs.push("--release");
}
- if (isZed2) {
- buildArgs.push("-p", "zed2");
- }
-
return buildArgs;
})();
const zedBinary = (() => {
const target = isReleaseMode ? "release" : "debug";
- const binary = isZed2 ? "Zed2" : "Zed";
-
- return `target/${target}/${binary}`;
+ return `target/${target}/Zed`;
})();
execFileSync("cargo", buildArgs, { stdio: "inherit" });