diff --git a/.github/workflows/release_nightly.yml b/.github/workflows/release_nightly.yml index 5063d414ec..63ff45f5be 100644 --- a/.github/workflows/release_nightly.yml +++ b/.github/workflows/release_nightly.yml @@ -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 diff --git a/Cargo.lock b/Cargo.lock index 815b73b37f..801711ef33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", @@ -7383,18 +7009,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "quick_action_bar" -version = "0.1.0" -dependencies = [ - "assistant", - "editor", - "gpui", - "search", - "theme", - "workspace", -] - [[package]] name = "quick_action_bar2" version = "0.1.0" @@ -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", ] @@ -9643,22 +9229,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "system-interface" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92adbaf536f5aff6986e1e62ba36cee72b1718c5153eee08b9e728ddde3f6029" -dependencies = [ - "atty", - "bitflags 1.3.2", - "cap-fs-ext", - "cap-std", - "io-lifetimes 0.7.5", - "rustix 0.35.16", - "windows-sys 0.36.1", - "winx", -] - [[package]] name = "taffy" version = "0.3.11" @@ -9789,41 +9359,6 @@ dependencies = [ "util", ] -[[package]] -name = "terminal_view" -version = "0.1.0" -dependencies = [ - "anyhow", - "client", - "context_menu", - "db", - "dirs 4.0.0", - "editor", - "futures 0.3.28", - "gpui", - "itertools 0.10.5", - "language", - "lazy_static", - "libc", - "mio-extras", - "ordered-float 2.10.0", - "procinfo", - "project", - "rand 0.8.5", - "search", - "serde", - "serde_derive", - "settings", - "shellexpand", - "smallvec", - "smol", - "terminal", - "theme", - "thiserror", - "util", - "workspace", -] - [[package]] name = "terminal_view2" version = "0.1.0" @@ -9867,7 +9402,7 @@ dependencies = [ "collections", "ctor", "digest 0.9.0", - "env_logger 0.9.3", + "env_logger", "gpui", "lazy_static", "log", @@ -9890,7 +9425,7 @@ dependencies = [ "collections", "ctor", "digest 0.9.0", - "env_logger 0.9.3", + "env_logger", "gpui2", "lazy_static", "log", @@ -10479,7 +10014,7 @@ source = "git+https://github.com/tree-sitter/tree-sitter?rev=31c40449749c4263a91 dependencies = [ "cc", "regex", - "wasmtime 16.0.0", + "wasmtime", "wasmtime-c-api-impl", ] @@ -11227,48 +10762,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasi-cap-std-sync" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4b4953999c746173c263b81e9e5e3e335ff47face7187ba2a5ecc91c716e6f3" -dependencies = [ - "anyhow", - "async-trait", - "cap-fs-ext", - "cap-rand", - "cap-std", - "cap-time-ext", - "fs-set-times", - "io-extras", - "io-lifetimes 0.7.5", - "is-terminal 0.3.0", - "once_cell", - "rustix 0.35.16", - "system-interface", - "tracing", - "wasi-common", - "windows-sys 0.36.1", -] - -[[package]] -name = "wasi-common" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d47faf4f76ebfdeb1f3346a949c6fbf2f2471afc68280b00c76d6c02221d80ad" -dependencies = [ - "anyhow", - "bitflags 1.3.2", - "cap-rand", - "cap-std", - "io-extras", - "rustix 0.35.16", - "thiserror", - "tracing", - "wiggle", - "windows-sys 0.36.1", -] - [[package]] name = "wasm-bindgen" version = "0.2.87" @@ -11344,15 +10837,6 @@ dependencies = [ "leb128", ] -[[package]] -name = "wasmparser" -version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da34cec2a8c23db906cdf8b26e988d7a7f0d549eb5d51299129647af61a1b37" -dependencies = [ - "indexmap 1.9.3", -] - [[package]] name = "wasmparser" version = "0.118.1" @@ -11363,37 +10847,6 @@ dependencies = [ "semver", ] -[[package]] -name = "wasmtime" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743d37c265fa134a76de653c7e66be22590eaccd03da13cee99f3ac7a59cb826" -dependencies = [ - "anyhow", - "async-trait", - "bincode", - "cfg-if 1.0.0", - "indexmap 1.9.3", - "libc", - "log", - "object 0.29.0", - "once_cell", - "paste", - "psm", - "rayon", - "serde", - "target-lexicon", - "wasmparser 0.92.0", - "wasmtime-cache", - "wasmtime-cranelift 2.0.2", - "wasmtime-environ 2.0.2", - "wasmtime-fiber", - "wasmtime-jit 2.0.2", - "wasmtime-runtime 2.0.2", - "wat", - "windows-sys 0.36.1", -] - [[package]] name = "wasmtime" version = "16.0.0" @@ -11406,30 +10859,21 @@ dependencies = [ "indexmap 2.0.0", "libc", "log", - "object 0.32.1", + "object", "once_cell", "paste", "serde", "serde_derive", "serde_json", "target-lexicon", - "wasmparser 0.118.1", - "wasmtime-cranelift 16.0.0", - "wasmtime-environ 16.0.0", - "wasmtime-jit 16.0.0", - "wasmtime-runtime 16.0.0", + "wasmparser", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", "windows-sys 0.48.0", ] -[[package]] -name = "wasmtime-asm-macros" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de327cf46d5218315957138131ed904621e6f99018aa2da508c0dcf0c65f1bf2" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "wasmtime-asm-macros" version = "16.0.0" @@ -11447,7 +10891,7 @@ dependencies = [ "log", "once_cell", "tracing", - "wasmtime 16.0.0", + "wasmtime", "wasmtime-c-api-macros", ] @@ -11460,47 +10904,6 @@ dependencies = [ "quote", ] -[[package]] -name = "wasmtime-cache" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bd53d27df1076100519b680b45d8209aed62b4bbaf0913732810cb216f7b2b" -dependencies = [ - "anyhow", - "base64 0.13.1", - "bincode", - "directories-next", - "file-per-thread-logger", - "log", - "rustix 0.35.16", - "serde", - "sha2 0.9.9", - "toml 0.5.11", - "windows-sys 0.36.1", - "zstd", -] - -[[package]] -name = "wasmtime-cranelift" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017c3605ccce867b3ba7f71d95e5652acc22b9dc2971ad6a6f9df4a8d7af2648" -dependencies = [ - "anyhow", - "cranelift-codegen 0.89.2", - "cranelift-entity 0.89.2", - "cranelift-frontend 0.89.2", - "cranelift-native 0.89.2", - "cranelift-wasm 0.89.2", - "gimli 0.26.2", - "log", - "object 0.29.0", - "target-lexicon", - "thiserror", - "wasmparser 0.92.0", - "wasmtime-environ 2.0.2", -] - [[package]] name = "wasmtime-cranelift" version = "16.0.0" @@ -11508,20 +10911,20 @@ source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e dependencies = [ "anyhow", "cfg-if 1.0.0", - "cranelift-codegen 0.103.0", + "cranelift-codegen", "cranelift-control", - "cranelift-entity 0.103.0", - "cranelift-frontend 0.103.0", - "cranelift-native 0.103.0", - "cranelift-wasm 0.103.0", - "gimli 0.28.0", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", "log", - "object 0.32.1", + "object", "target-lexicon", "thiserror", - "wasmparser 0.118.1", + "wasmparser", "wasmtime-cranelift-shared", - "wasmtime-environ 16.0.0", + "wasmtime-environ", "wasmtime-versioned-export-macros", ] @@ -11531,32 +10934,13 @@ version = "16.0.0" source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" dependencies = [ "anyhow", - "cranelift-codegen 0.103.0", + "cranelift-codegen", "cranelift-control", - "cranelift-native 0.103.0", - "gimli 0.28.0", - "object 0.32.1", + "cranelift-native", + "gimli", + "object", "target-lexicon", - "wasmtime-environ 16.0.0", -] - -[[package]] -name = "wasmtime-environ" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aec5c1f81aab9bb35997113c171b6bb9093afc90e3757c55e0c08dc9ac612e4" -dependencies = [ - "anyhow", - "cranelift-entity 0.89.2", - "gimli 0.26.2", - "indexmap 1.9.3", - "log", - "object 0.29.0", - "serde", - "target-lexicon", - "thiserror", - "wasmparser 0.92.0", - "wasmtime-types 2.0.2", + "wasmtime-environ", ] [[package]] @@ -11565,56 +10949,17 @@ version = "16.0.0" source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" dependencies = [ "anyhow", - "cranelift-entity 0.103.0", - "gimli 0.28.0", + "cranelift-entity", + "gimli", "indexmap 2.0.0", "log", - "object 0.32.1", + "object", "serde", "serde_derive", "target-lexicon", "thiserror", - "wasmparser 0.118.1", - "wasmtime-types 16.0.0", -] - -[[package]] -name = "wasmtime-fiber" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1075aa43857086ef89afbe87602fe2dae98ad212582e722b6d3d2676bb5ee141" -dependencies = [ - "cc", - "cfg-if 1.0.0", - "rustix 0.35.16", - "wasmtime-asm-macros 2.0.2", - "windows-sys 0.36.1", -] - -[[package]] -name = "wasmtime-jit" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c683893dbba3986aa71582a5332b87157fb95d34098de2e5f077c7f078726d" -dependencies = [ - "addr2line 0.17.0", - "anyhow", - "bincode", - "cfg-if 1.0.0", - "cpp_demangle", - "gimli 0.26.2", - "ittapi", - "log", - "object 0.29.0", - "rustc-demangle", - "rustix 0.35.16", - "serde", - "target-lexicon", - "thiserror", - "wasmtime-environ 2.0.2", - "wasmtime-jit-debug", - "wasmtime-runtime 2.0.2", - "windows-sys 0.36.1", + "wasmparser", + "wasmtime-types", ] [[package]] @@ -11625,30 +10970,19 @@ dependencies = [ "anyhow", "bincode", "cfg-if 1.0.0", - "gimli 0.28.0", + "gimli", "log", - "object 0.32.1", + "object", "rustix 0.38.21", "serde", "serde_derive", "target-lexicon", - "wasmtime-environ 16.0.0", + "wasmtime-environ", "wasmtime-jit-icache-coherence", - "wasmtime-runtime 16.0.0", + "wasmtime-runtime", "windows-sys 0.48.0", ] -[[package]] -name = "wasmtime-jit-debug" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2f8f15a81292eec468c79a4f887a37a3d02eb0c610f34ddbec607d3e9022f18" -dependencies = [ - "object 0.29.0", - "once_cell", - "rustix 0.35.16", -] - [[package]] name = "wasmtime-jit-icache-coherence" version = "16.0.0" @@ -11659,32 +10993,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "wasmtime-runtime" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09af6238c962e8220424c815a7b1a9a6d0ba0694f0ab0ae12a6cda1923935a0d" -dependencies = [ - "anyhow", - "cc", - "cfg-if 1.0.0", - "indexmap 1.9.3", - "libc", - "log", - "mach", - "memfd", - "memoffset 0.6.5", - "paste", - "rand 0.8.5", - "rustix 0.35.16", - "thiserror", - "wasmtime-asm-macros 2.0.2", - "wasmtime-environ 2.0.2", - "wasmtime-fiber", - "wasmtime-jit-debug", - "windows-sys 0.36.1", -] - [[package]] name = "wasmtime-runtime" version = "16.0.0" @@ -11704,35 +11012,23 @@ dependencies = [ "rustix 0.38.21", "sptr", "wasm-encoder", - "wasmtime-asm-macros 16.0.0", - "wasmtime-environ 16.0.0", + "wasmtime-asm-macros", + "wasmtime-environ", "wasmtime-versioned-export-macros", "wasmtime-wmemcheck", "windows-sys 0.48.0", ] -[[package]] -name = "wasmtime-types" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc3dd9521815984b35d6362f79e6b9c72475027cd1c71c44eb8df8fbf33a9fb" -dependencies = [ - "cranelift-entity 0.89.2", - "serde", - "thiserror", - "wasmparser 0.92.0", -] - [[package]] name = "wasmtime-types" version = "16.0.0" source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" dependencies = [ - "cranelift-entity 0.103.0", + "cranelift-entity", "serde", "serde_derive", "thiserror", - "wasmparser 0.118.1", + "wasmparser", ] [[package]] @@ -11745,54 +11041,11 @@ dependencies = [ "syn 2.0.37", ] -[[package]] -name = "wasmtime-wasi" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3bba5cc0a940cef3fbbfa7291c7e5fe0f7ec6fb2efa7bd1504032ed6202a1c0" -dependencies = [ - "anyhow", - "wasi-cap-std-sync", - "wasi-common", - "wasmtime 2.0.2", - "wiggle", -] - [[package]] name = "wasmtime-wmemcheck" version = "16.0.0" source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" -[[package]] -name = "wast" -version = "35.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" -dependencies = [ - "leb128", -] - -[[package]] -name = "wast" -version = "69.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ee37317321afde358e4d7593745942c48d6d17e0e6e943704de9bbee121e7a" -dependencies = [ - "leb128", - "memchr", - "unicode-width", - "wasm-encoder", -] - -[[package]] -name = "wat" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb338ee8dee4d4cd05e6426683f21c5087dc7cfc8903e839ccf48d43332da3c" -dependencies = [ - "wast 69.0.1", -] - [[package]] name = "web-sys" version = "0.3.64" @@ -11906,48 +11159,6 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" -[[package]] -name = "wiggle" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "211ef4d238fd83bbe6f1bc57f3e2e20dc8b1f999188be252e7a535b696c6f84f" -dependencies = [ - "anyhow", - "async-trait", - "bitflags 1.3.2", - "thiserror", - "tracing", - "wasmtime 2.0.2", - "wiggle-macro", -] - -[[package]] -name = "wiggle-generate" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63feec26b2fc3708c7a63316949ca75dd96988f03a17e4cb8d533dc62587ada4" -dependencies = [ - "anyhow", - "heck 0.4.1", - "proc-macro2", - "quote", - "shellexpand", - "syn 1.0.109", - "witx", -] - -[[package]] -name = "wiggle-macro" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494dc2646618c2b7fb0ec5e1d27dbac5ca31194c00a64698a4b5b35a83d80c21" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "wiggle-generate", -] - [[package]] name = "winapi" version = "0.2.8" @@ -12009,34 +11220,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -12055,15 +11238,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - [[package]] name = "windows-targets" version = "0.42.2" @@ -12094,21 +11268,6 @@ dependencies = [ "windows_x86_64_msvc 0.48.5", ] -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -12121,18 +11280,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -12145,18 +11292,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -12169,18 +11304,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -12193,18 +11316,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -12217,12 +11328,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -12235,18 +11340,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -12259,12 +11352,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - [[package]] name = "winnow" version = "0.5.15" @@ -12284,17 +11371,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winx" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b01e010390eb263a4518c8cebf86cb67469d1511c00b749a47b64c39e8054d" -dependencies = [ - "bitflags 1.3.2", - "io-lifetimes 0.7.5", - "windows-sys 0.36.1", -] - [[package]] name = "wio" version = "0.2.2" @@ -12304,18 +11380,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "witx" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" -dependencies = [ - "anyhow", - "log", - "thiserror", - "wast 35.0.2", -] - [[package]] name = "workspace" version = "0.1.0" @@ -12329,7 +11393,7 @@ dependencies = [ "context_menu", "db", "drag_and_drop", - "env_logger 0.9.3", + "env_logger", "fs", "futures 0.3.28", "gpui", @@ -12367,7 +11431,7 @@ dependencies = [ "client2", "collections", "db2", - "env_logger 0.9.3", + "env_logger", "fs2", "futures 0.3.28", "gpui2", @@ -12475,147 +11539,6 @@ dependencies = [ [[package]] name = "zed" version = "0.119.0" -dependencies = [ - "activity_indicator", - "ai", - "anyhow", - "assistant", - "async-compression", - "async-recursion 0.3.2", - "async-tar", - "async-trait", - "audio", - "auto_update", - "backtrace", - "breadcrumbs", - "call", - "channel", - "chrono", - "cli", - "client", - "clock", - "collab_ui", - "collections", - "command_palette", - "component_test", - "context_menu", - "copilot", - "copilot_button", - "ctor", - "db", - "diagnostics", - "editor", - "env_logger 0.9.3", - "feature_flags", - "feedback", - "file_finder", - "fs", - "fsevent", - "futures 0.3.28", - "fuzzy", - "go_to_line", - "gpui", - "ignore", - "image", - "indexmap 1.9.3", - "install_cli", - "isahc", - "journal", - "language", - "language_selector", - "language_tools", - "lazy_static", - "libc", - "log", - "lsp", - "node_runtime", - "notifications", - "num_cpus", - "outline", - "parking_lot 0.11.2", - "plugin_runtime", - "postage", - "project", - "project_panel", - "project_symbols", - "quick_action_bar", - "rand 0.8.5", - "recent_projects", - "regex", - "rpc", - "rsa 0.4.0", - "rust-embed", - "schemars", - "search", - "semantic_index", - "serde", - "serde_derive", - "serde_json", - "settings", - "shellexpand", - "simplelog", - "smallvec", - "smol", - "sum_tree", - "tempdir", - "terminal_view", - "text", - "theme", - "theme_selector", - "thiserror", - "tiny_http", - "toml 0.5.11", - "tree-sitter", - "tree-sitter-bash", - "tree-sitter-c", - "tree-sitter-cpp", - "tree-sitter-css", - "tree-sitter-elixir", - "tree-sitter-elm", - "tree-sitter-embedded-template", - "tree-sitter-glsl", - "tree-sitter-go", - "tree-sitter-heex", - "tree-sitter-html", - "tree-sitter-json 0.20.0", - "tree-sitter-lua", - "tree-sitter-markdown", - "tree-sitter-nix", - "tree-sitter-nu", - "tree-sitter-php", - "tree-sitter-python", - "tree-sitter-racket", - "tree-sitter-ruby", - "tree-sitter-rust", - "tree-sitter-scheme", - "tree-sitter-svelte", - "tree-sitter-toml", - "tree-sitter-typescript", - "tree-sitter-uiua", - "tree-sitter-vue", - "tree-sitter-yaml", - "unindent", - "url", - "urlencoding", - "util", - "uuid 1.4.1", - "vim", - "welcome", - "workspace", - "zed-actions", -] - -[[package]] -name = "zed-actions" -version = "0.1.0" -dependencies = [ - "gpui", - "serde", -] - -[[package]] -name = "zed2" -version = "2.0.0" dependencies = [ "activity_indicator2", "ai2", @@ -12643,7 +11566,7 @@ dependencies = [ "db2", "diagnostics2", "editor2", - "env_logger 0.9.3", + "env_logger", "feature_flags2", "feedback2", "file_finder2", @@ -12743,6 +11666,14 @@ dependencies = [ "zed_actions2", ] +[[package]] +name = "zed-actions" +version = "0.1.0" +dependencies = [ + "gpui", + "serde", +] + [[package]] name = "zed_actions2" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 3ba64e4530..b26b084ede 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -129,7 +129,6 @@ members = [ "crates/welcome2", "crates/xtask", "crates/zed", - "crates/zed2", "crates/zed-actions", "crates/zed_actions2" ] diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 53a5c1cdde..24e0644560 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["Nathan Sobo "] 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" diff --git a/crates/zed/build.rs b/crates/zed/build.rs index b83afba747..08608d0c6a 100644 --- a/crates/zed/build.rs +++ b/crates/zed/build.rs @@ -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(); - // 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:rustc-env=ZED_COMMIT_SHA={git_sha}"); - println!("cargo:rerun-if-changed=../../styles/src"); + 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" + ); + } + } + } + } } diff --git a/crates/zed/examples/semantic_index_eval.rs b/crates/zed/examples/semantic_index_eval.rs deleted file mode 100644 index caf8e5f5c7..0000000000 --- a/crates/zed/examples/semantic_index_eval.rs +++ /dev/null @@ -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, -} - -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::().unwrap())); - } - } - } - pairs - } -} - -#[derive(Deserialize, Clone)] -struct RepoEval { - repo: String, - commit: String, - assertions: Vec, -} - -const TMP_REPO_PATH: &str = "eval_repos"; - -fn parse_eval() -> anyhow::Result> { - let eval_folder = env::current_dir()? - .as_path() - .parent() - .unwrap() - .join("zed/crates/semantic_index/eval"); - - let mut repo_evals: Vec = 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) -> 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, - k: usize, - cx: &AsyncAppContext, -) -> (Vec, Vec) { - 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, ideal: Vec) -> Vec { - // 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) -> Vec { - let mut map_at_k = Vec::new(); - - let non_zero = hits.iter().sum::() 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) -> 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, - map: Vec, - mrr: f32, - hits: Vec, - precision: Vec, - recall: Vec, -} - -#[derive(Serialize)] -struct SummaryMetrics { - millis_to_search: f32, - ndcg: Vec, - map: Vec, - mrr: f32, - precision: Vec, - recall: Vec, -} - -#[derive(Serialize)] -struct RepoEvaluationMetrics { - millis_to_index: Duration, - query_metrics: Vec, - repo_metrics: Option, -} - -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::() 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::>(); - let map = map_sum.iter().map(|val| val / l).collect::>(); - let precision = precision_sum - .iter() - .map(|val| val / l) - .collect::>(); - let recall = recall_sum.iter().map(|val| val / l).collect::>(); - let mrr = mmr_sum / l; - - self.repo_metrics = Some(SummaryMetrics { - millis_to_search, - ndcg, - map, - mrr, - precision, - recall, - }) - } -} - -fn evaluate_precision(hits: Vec) -> Vec { - 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, ideal: Vec) -> Vec { - let total_relevant = ideal.iter().sum::() 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, - project: ModelHandle, - query_matches: Vec, - cx: &mut AsyncAppContext, -) -> Result { - // 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::(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(); - }); -} diff --git a/crates/zed2/src/app_menus.rs b/crates/zed/src/app_menus.rs similarity index 100% rename from crates/zed2/src/app_menus.rs rename to crates/zed/src/app_menus.rs diff --git a/crates/zed/src/assets.rs b/crates/zed/src/assets.rs index 574016c25d..5d5e81a60e 100644 --- a/crates/zed/src/assets.rs +++ b/crates/zed/src/assets.rs @@ -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> { - Self::iter().filter(|p| p.starts_with(path)).collect() + fn list(&self, path: &str) -> Result> { + Ok(Self::iter() + .filter_map(|p| { + if p.starts_with(path) { + Some(p.into()) + } else { + None + } + }) + .collect()) } } diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index 5ade8cb302..3fdcad46fe 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -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, cx: &mut AppContext, ) { - settings::register::(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::(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"))] diff --git a/crates/zed/src/languages/c.rs b/crates/zed/src/languages/c.rs index 27a65570b6..a0b00d7797 100644 --- a/crates/zed/src/languages/c.rs +++ b/crates/zed/src/languages/c.rs @@ -273,18 +273,19 @@ async fn get_cached_server_binary(container_dir: PathBuf) -> Option(|store, cx| { + cx.update_global::(|store, cx| { store.update_user_settings::(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); diff --git a/crates/zed/src/languages/elixir.rs b/crates/zed/src/languages/elixir.rs index e2c79570bc..90352c78b4 100644 --- a/crates/zed/src/languages/elixir.rs +++ b/crates/zed/src/languages/elixir.rs @@ -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, } -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 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")); } diff --git a/crates/zed/src/languages/elixir/embedding.scm b/crates/zed/src/languages/elixir/embedding.scm index 743ebe4d2f..16ad20746d 100644 --- a/crates/zed/src/languages/elixir/embedding.scm +++ b/crates/zed/src/languages/elixir/embedding.scm @@ -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 diff --git a/crates/zed/src/languages/go.rs b/crates/zed/src/languages/go.rs index 19b7013709..0daf1527c3 100644 --- a/crates/zed/src/languages/go.rs +++ b/crates/zed/src/languages/go.rs @@ -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); diff --git a/crates/zed/src/languages/json.rs b/crates/zed/src/languages/json.rs index 891c25c31f..162d4c9fdb 100644 --- a/crates/zed/src/languages/json.rs +++ b/crates/zed/src/languages/json.rs @@ -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::>(); + 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::().json_schema( diff --git a/crates/zed/src/languages/language_plugin.rs b/crates/zed/src/languages/language_plugin.rs index b2405d8bb8..968cc819fd 100644 --- a/crates/zed/src/languages/language_plugin.rs +++ b/crates/zed/src/languages/language_plugin.rs @@ -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; diff --git a/crates/zed/src/languages/nu.rs b/crates/zed/src/languages/nu.rs index 16a3b0e4c0..a3631b8471 100644 --- a/crates/zed/src/languages/nu.rs +++ b/crates/zed/src/languages/nu.rs @@ -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 { None } - - async fn label_for_completion( - &self, - completion: &lsp::CompletionItem, - language: &Arc, - ) -> Option { - 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, - ) -> Option { - Some(CodeLabel { - runs: language.highlight_text(&name.into(), 0..name.len()), - text: name.to_string(), - filter_range: 0..name.len(), - }) - } } diff --git a/crates/zed/src/languages/python.rs b/crates/zed/src/languages/python.rs index c10d605a38..d28cd9f6e4 100644 --- a/crates/zed/src/languages/python.rs +++ b/crates/zed/src/languages/python.rs @@ -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::(|store, cx| { + cx.update_global::(|store, cx| { store.update_user_settings::(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| { let ix = buffer.len(); buffer.edit([(ix..ix, text)], Some(AutoindentMode::EachLine), cx); diff --git a/crates/zed/src/languages/rust.rs b/crates/zed/src/languages/rust.rs index dc2697ab19..6f6ffa4188 100644 --- a/crates/zed/src/languages/rust.rs +++ b/crates/zed/src/languages/rust.rs @@ -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::(|store, cx| { + cx.update_global::(|store, cx| { store.update_user_settings::(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); diff --git a/crates/zed/src/languages/typescript.rs b/crates/zed/src/languages/typescript.rs index fbb14930fc..de25f2ead8 100644 --- a/crates/zed/src/languages/typescript.rs +++ b/crates/zed/src/languages/typescript.rs @@ -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 diff --git a/crates/zed/src/languages/uiua/config.toml b/crates/zed/src/languages/uiua/config.toml index 87c0d8a9db..72fdc91040 100644 --- a/crates/zed/src/languages/uiua/config.toml +++ b/crates/zed/src/languages/uiua/config.toml @@ -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"] }, diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 831a5bb8de..eb72423b72 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -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::>() { - if let Some(app_state) = cx.global::>().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::>() { + if let Some(app_state) = cx.global::>().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::({ + languages.set_theme(cx.theme().clone()); + cx.observe_global::({ 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::(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, + 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, 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, 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, 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, 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, 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, session_id: Strin } fn upload_previous_panics(http: Arc, cx: &mut AppContext) { - let telemetry_settings = *settings::get::(cx); + let telemetry_settings = *client::TelemetrySettings::get_global(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(); + 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 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 !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")?; + 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(|| { + 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 - }); + ); + None + }); - if let Some(panic) = panic { - let body = serde_json::to_string(&PanicRequest { - panic, - token: ZED_SECRET_CLIENT_TOKEN.into(), - }) - .unwrap(); + 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() - ); - } + 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 { .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, 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, languages: Arc) -> Option<()> { + use std::time::Duration; -#[cfg(debug_assertions)] -async fn watch_languages(fs: Arc, languages: Arc) -> 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, languages: Arc) -> O } #[cfg(debug_assertions)] -fn watch_file_types(fs: Arc, cx: &mut AppContext) { - cx.spawn(|mut cx| async move { +fn watch_file_types(fs: Arc, 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, cx: &mut AppContext) { *file_types = project_panel::file_associations::FileAssociations::new(Assets); }); }) + .ok(); } }) .detach() } #[cfg(not(debug_assertions))] -async fn watch_themes(_fs: Arc, _cx: AsyncAppContext) -> Option<()> { +async fn watch_languages(_: Arc, _: Arc) -> Option<()> { None } #[cfg(not(debug_assertions))] -async fn watch_languages(_: Arc, _: Arc) -> Option<()> { - None -} - -#[cfg(not(debug_assertions))] -fn watch_file_types(_fs: Arc, _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, _cx: &mut AppContext) {} diff --git a/crates/zed/src/menus.rs b/crates/zed/src/menus.rs deleted file mode 100644 index 4e01693dbf..0000000000 --- a/crates/zed/src/menus.rs +++ /dev/null @@ -1,174 +0,0 @@ -use gpui::{Menu, MenuItem, OsAction}; - -#[cfg(target_os = "macos")] -pub fn menus() -> Vec> { - 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(), - }, - ), - ], - }, - ] -} diff --git a/crates/zed/src/open_listener.rs b/crates/zed/src/open_listener.rs index e0b360d0d7..6db020a785 100644 --- a/crates/zed/src/open_listener.rs +++ b/crates/zed/src/open_listener.rs @@ -54,7 +54,7 @@ impl OpenListener { ) } - pub fn open_urls(&self, urls: Vec) { + 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) -> Option { + fn handle_file_urls(&self, urls: &[String]) -> Option { 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::() { - 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::() { + 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 diff --git a/crates/zed/src/test.rs b/crates/zed/src/test.rs deleted file mode 100644 index 67622db83f..0000000000 --- a/crates/zed/src/test.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -#[ctor::ctor] -fn init_logger() { - if std::env::var("RUST_LOG").is_ok() { - env_logger::init(); - } -} diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index d0a5267483..bcfdb848ab 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -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; +mod only_instance; +mod open_listener; -use anyhow::Context; -use assets::Assets; +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::*; +use zed_actions::{OpenBrowser, OpenSettings, OpenZedURL, Quit}; -#[derive(Deserialize, Clone, PartialEq)] -pub struct OpenBrowser { - url: Arc, -} - -impl_actions!(zed, [OpenBrowser]); - -pub fn init(app_state: &Arc, 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| { - cx.minimize_window(); - }, - ); - cx.add_action( - |_: &mut Workspace, _: &Zoom, cx: &mut ViewContext| { - cx.zoom_window(); - }, - ); - cx.add_action( - |_: &mut Workspace, _: &ToggleFullScreen, cx: &mut ViewContext| { - cx.toggle_full_screen(); - }, - ); - cx.add_global_action(quit); - cx.add_global_action(move |action: &OpenZedURL, cx| { - cx.global::>() - .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| { - open_log_file(workspace, cx); - }, - ); - cx.add_action( - move |workspace: &mut Workspace, _: &OpenLicenses, cx: &mut ViewContext| { - open_bundled_file( - workspace, - asset_str::("licenses.md"), - "Open Source License Attribution", - "Markdown", - cx, - ); - }, - ); - cx.add_action( - move |workspace: &mut Workspace, _: &OpenTelemetryLog, cx: &mut ViewContext| { - open_telemetry_log_file(workspace, cx); - }, - ); - cx.add_action( - move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext| { - 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| { - 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| { - open_bundled_file( - workspace, - settings::default_keymap(), - "Default Key Bindings", - "JSON", - cx, - ); - }, - ); - cx.add_action( - move |workspace: &mut Workspace, - _: &OpenDefaultSettings, - cx: &mut ViewContext| { - open_bundled_file( - workspace, - settings::default_settings(), - "Default Settings", - "JSON", - cx, - ); - }, - ); - cx.add_action({ - move |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext| { - 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.toggle_panel_focus::(cx); - }, - ); - cx.add_action( - |workspace: &mut Workspace, - _: &collab_ui::collab_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace.toggle_panel_focus::(cx); - }, - ); - cx.add_action( - |workspace: &mut Workspace, - _: &collab_ui::chat_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace.toggle_panel_focus::(cx); - }, - ); - cx.add_action( - |workspace: &mut Workspace, - _: &collab_ui::notification_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace.toggle_panel_focus::(cx); - }, - ); - cx.add_action( - |workspace: &mut Workspace, - _: &terminal_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace.toggle_panel_focus::(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(); - } - } - }); - load_default_keymap(cx); -} - -pub fn initialize_workspace( - workspace_handle: WeakViewHandle, - was_deserialized: bool, - app_state: Arc, - cx: AsyncAppContext, -) -> Task> { - 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); - }) - }); - } - } - }) - .detach(); - - cx.emit(workspace::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.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); - }); - - auto_update::notify_of_any_new_update(cx.weak_handle(), cx); - - vim::observe_keystrokes(cx); - - cx.on_window_should_close(|workspace, cx| { - if let Some(task) = workspace.close(&Default::default(), cx) { - task.detach_and_log_err(cx); - } - 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::(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(()) - }) -} +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, - display: Option, - platform: &dyn Platform, -) -> WindowOptions<'static> { + display_uuid: Option, + cx: &mut AppContext, +) -> WindowOptions { let bounds = bounds.unwrap_or(WindowBounds::Maximized); - let screen = display.and_then(|display| platform.screen_by_id(display)); + 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(vec2f(8., 8.)), + traffic_light_position: Some(point(px(8.), px(8.))), }), center: false, focus: false, show: false, kind: WindowKind::Normal, is_movable: true, - bounds, - screen, + display_id: display.map(|display| display.id()), } } -fn quit(_: &Quit, cx: &mut gpui::AppContext) { - let should_confirm = settings::get::(cx).confirm_quit; - cx.spawn(|mut cx| async move { - let mut workspace_windows = cx - .windows() - .into_iter() - .filter_map(|window| window.downcast::()) - .collect::>(); +pub fn initialize_workspace(app_state: Arc, 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::>() + .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::("licenses.md"), + "Open Source License Attribution", + "Markdown", + cx, + ); + }) + .register_action( + move |workspace: &mut Workspace, + _: &OpenTelemetryLog, + cx: &mut ViewContext| { + open_telemetry_log_file(workspace, cx); + }, + ) + .register_action( + move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext| { + create_and_open_local_file(&paths::KEYMAP, cx, Default::default) + .detach_and_log_err(cx); + }, + ) + .register_action( + move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext| { + 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| { + open_bundled_file( + workspace, + settings::default_keymap(), + "Default Key Bindings", + "JSON", + cx, + ); + }, + ) + .register_action( + move |workspace: &mut Workspace, + _: &OpenDefaultSettings, + cx: &mut ViewContext| { + open_bundled_file( + workspace, + settings::default_settings(), + "Default Settings", + "JSON", + cx, + ); + }, + ) + //todo!() + // cx.add_action({ + // move |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext| { + // 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.toggle_panel_focus::(cx); + // }, + // ); + // cx.add_action( + // |workspace: &mut Workspace, + // _: &collab_ui::collab_panel::ToggleFocus, + // cx: &mut ViewContext| { + // workspace.toggle_panel_focus::(cx); + // }, + // ); + // cx.add_action( + // |workspace: &mut Workspace, + // _: &collab_ui::chat_panel::ToggleFocus, + // cx: &mut ViewContext| { + // workspace.toggle_panel_focus::(cx); + // }, + // ); + // cx.add_action( + // |workspace: &mut Workspace, + // _: &collab_ui::notification_panel::ToggleFocus, + // cx: &mut ViewContext| { + // workspace.toggle_panel_focus::(cx); + // }, + // ); + // cx.add_action( + // |workspace: &mut Workspace, + // _: &terminal_panel::ToggleFocus, + // cx: &mut ViewContext| { + // workspace.toggle_panel_focus::(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, cx: &mut ViewContext) { + 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) { + use std::fmt::Write as _; + + let app_name = cx.global::().display_name(); + let version = env!("CARGO_PKG_VERSION"); + let mut message = format!("{app_name} {version}"); + if let Some(sha) = cx.try_global::() { + 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) { + 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::()) + .collect::>() + })?; // 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)); + cx.update(|_, cx| { + workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false)); + }) + .log_err(); - 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, - ); + 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) { - let app_name = cx.global::().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) { 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) { .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) { .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::(cx).asset_path() { - KeymapFile::load_asset(asset_path, cx).unwrap(); - } -} - pub fn handle_keymap_file_changes( mut user_keymap_file_rx: mpsc::UnboundedReceiver, 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)); + if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() { + cx.update(|cx| reload_keymaps(cx, &keymap_content)).ok(); - let mut old_base_keymap = cx.read(|cx| *settings::get::(cx)); - drop(settings_subscription); - settings_subscription = Some(cx.update(|cx| { - cx.observe_global::(move |cx| { - let new_base_keymap = *settings::get::(cx); - if new_base_keymap != old_base_keymap { - old_base_keymap = new_base_keymap.clone(); - reload_keymaps(cx, &keymap_content); - } - }) - })); + // todo!() + // let mut old_base_keymap = cx.read(|cx| *settings::get::(cx)); + // drop(settings_subscription); + // settings_subscription = Some(cx.update(|cx| { + // cx.observe_global::(move |cx| { + // let new_base_keymap = *settings::get::(cx); + // if new_base_keymap != old_base_keymap { + // old_base_keymap = new_base_keymap.clone(); + // reload_keymaps(cx, &keymap_content); + // } + // }) + // })); } } }) @@ -588,10 +589,11 @@ pub fn handle_keymap_file_changes( } fn reload_keymaps(cx: &mut AppContext, keymap_content: &KeymapFile) { - cx.clear_bindings(); + // todo!() + // cx.clear_bindings(); load_default_keymap(cx); keymap_content.clone().add_to_cx(cx).log_err(); - cx.set_menus(menus::menus()); + cx.set_menus(app_menus()); } fn open_local_settings_file( @@ -610,21 +612,21 @@ fn open_local_settings_file( let file_path = &*LOCAL_SETTINGS_RELATIVE_PATH; if let Some(dir_path) = file_path.parent() { - if worktree.read_with(&cx, |tree, _| tree.entry_for_path(dir_path).is_none()) { + 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.read_with(&cx, |tree, _| tree.entry_for_path(file_path).is_none()) { + 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")?; } @@ -655,7 +657,7 @@ fn open_local_settings_file( .detach(); } else { workspace.show_notification(0, cx, |cx| { - cx.add_view(|_| MessageNotification::new("This project has no folders open.")) + cx.new_view(|_| MessageNotification::new("This project has no folders open.")) }) } } @@ -702,11 +704,11 @@ fn open_telemetry_log_file(workspace: &mut Workspace, cx: &mut ViewContext().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::().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::().unwrap().root(cx); - workspace_1.update(cx, |workspace, cx| { - assert_eq!( - workspace - .worktrees(cx) - .map(|w| w.read(cx).abs_path()) - .collect::>(), - &[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, 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::().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::() - .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::() - .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::() - .unwrap(); - let workspace = window.root(cx); - - let editor = workspace.update(cx, |workspace, cx| { - workspace - .active_item(cx) - .unwrap() - .downcast::() - .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::>(); - 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::().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::(), - workspace.right_dock().read(cx).panel::(), - workspace.bottom_dock().read(cx).panel::(), - ] - .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::() - .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::>(); - 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::() - .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::>(); - 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::() - .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::>(); - 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::>(); - 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::() - .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::(|store, cx| { - store.update_user_settings::(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::>() - }); - 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::>(); - 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::().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::() - .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::() - .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::() - .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::().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::().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::() - .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::() - .unwrap(); - let editor3 = workspace - .update(cx, |w, cx| w.open_path(file3.clone(), None, true, cx)) - .await - .unwrap() - .downcast::() - .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, - cx: &mut TestAppContext, - ) -> (ProjectPath, DisplayPoint, f32) { - workspace.update(cx, |workspace, cx| { - let item = workspace.active_item(cx).unwrap(); - let editor = item.downcast::().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, - cx: &TestAppContext, - ) -> Option { - 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) -> AnyElement { - 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) -> AnyElement { - 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::(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 { - 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 { - Arc::new(language::Language::new( - language::LanguageConfig { - name: "Rust".into(), - path_suffixes: vec!["rs".to_string()], - ..Default::default() - }, - Some(tree_sitter_rust::language()), - )) - } -} +// 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::().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::().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::().unwrap().root(cx); +// workspace_1.update(cx, |workspace, cx| { +// assert_eq!( +// workspace +// .worktrees(cx) +// .map(|w| w.read(cx).abs_path()) +// .collect::>(), +// &[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, 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::().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::() +// .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::() +// .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::() +// .unwrap(); +// let workspace = window.root(cx); + +// let editor = workspace.update(cx, |workspace, cx| { +// workspace +// .active_item(cx) +// .unwrap() +// .downcast::() +// .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::>(); +// 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::().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::(), +// workspace.right_dock().read(cx).panel::(), +// workspace.bottom_dock().read(cx).panel::(), +// ] +// .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::() +// .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::>(); +// 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::() +// .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::>(); +// 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::() +// .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::>(); +// 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::>(); +// 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::() +// .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::(|store, cx| { +// store.update_user_settings::(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::>() +// }); +// 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::>(); +// 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::().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::() +// .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::() +// .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::() +// .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::().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::().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::() +// .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::() +// .unwrap(); +// let editor3 = workspace +// .update(cx, |w, cx| w.open_path(file3.clone(), None, true, cx)) +// .await +// .unwrap() +// .downcast::() +// .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, +// cx: &mut TestAppContext, +// ) -> (ProjectPath, DisplayPoint, f32) { +// workspace.update(cx, |workspace, cx| { +// let item = workspace.active_item(cx).unwrap(); +// let editor = item.downcast::().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, +// cx: &TestAppContext, +// ) -> Option { +// 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) -> AnyElement { +// 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) -> AnyElement { +// 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::(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 { +// 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 { +// Arc::new(language::Language::new( +// language::LanguageConfig { +// name: "Rust".into(), +// path_suffixes: vec!["rs".to_string()], +// ..Default::default() +// }, +// Some(tree_sitter_rust::language()), +// )) +// } +// } diff --git a/crates/zed2/Cargo.toml b/crates/zed2/Cargo.toml deleted file mode 100644 index 3da22401e0..0000000000 --- a/crates/zed2/Cargo.toml +++ /dev/null @@ -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"] diff --git a/crates/zed2/build.rs b/crates/zed2/build.rs deleted file mode 100644 index 08608d0c6a..0000000000 --- a/crates/zed2/build.rs +++ /dev/null @@ -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" - ); - } - } - } - } -} diff --git a/crates/zed2/contents/dev/embedded.provisionprofile b/crates/zed2/contents/dev/embedded.provisionprofile deleted file mode 100644 index 8979e1fb9f..0000000000 Binary files a/crates/zed2/contents/dev/embedded.provisionprofile and /dev/null differ diff --git a/crates/zed2/contents/nightly/embedded.provisionprofile b/crates/zed2/contents/nightly/embedded.provisionprofile deleted file mode 100644 index 8979e1fb9f..0000000000 Binary files a/crates/zed2/contents/nightly/embedded.provisionprofile and /dev/null differ diff --git a/crates/zed2/contents/preview/embedded.provisionprofile b/crates/zed2/contents/preview/embedded.provisionprofile deleted file mode 100644 index 6eea317c37..0000000000 Binary files a/crates/zed2/contents/preview/embedded.provisionprofile and /dev/null differ diff --git a/crates/zed2/contents/stable/embedded.provisionprofile b/crates/zed2/contents/stable/embedded.provisionprofile deleted file mode 100644 index 0b2abe1838..0000000000 Binary files a/crates/zed2/contents/stable/embedded.provisionprofile and /dev/null differ diff --git a/crates/zed2/resources/app-icon-nightly.png b/crates/zed2/resources/app-icon-nightly.png deleted file mode 100644 index 35b3173478..0000000000 Binary files a/crates/zed2/resources/app-icon-nightly.png and /dev/null differ diff --git a/crates/zed2/resources/app-icon-nightly@2x.png b/crates/zed2/resources/app-icon-nightly@2x.png deleted file mode 100644 index 8766bc08ae..0000000000 Binary files a/crates/zed2/resources/app-icon-nightly@2x.png and /dev/null differ diff --git a/crates/zed2/resources/app-icon-preview.png b/crates/zed2/resources/app-icon-preview.png deleted file mode 100644 index b76e578858..0000000000 Binary files a/crates/zed2/resources/app-icon-preview.png and /dev/null differ diff --git a/crates/zed2/resources/app-icon-preview@2x.png b/crates/zed2/resources/app-icon-preview@2x.png deleted file mode 100644 index 6e08503927..0000000000 Binary files a/crates/zed2/resources/app-icon-preview@2x.png and /dev/null differ diff --git a/crates/zed2/resources/app-icon.png b/crates/zed2/resources/app-icon.png deleted file mode 100644 index 08b6d8afa0..0000000000 Binary files a/crates/zed2/resources/app-icon.png and /dev/null differ diff --git a/crates/zed2/resources/app-icon@2x.png b/crates/zed2/resources/app-icon@2x.png deleted file mode 100644 index 5bb5754bc1..0000000000 Binary files a/crates/zed2/resources/app-icon@2x.png and /dev/null differ diff --git a/crates/zed2/resources/info/DocumentTypes.plist b/crates/zed2/resources/info/DocumentTypes.plist deleted file mode 100644 index d043fa8ab9..0000000000 --- a/crates/zed2/resources/info/DocumentTypes.plist +++ /dev/null @@ -1,62 +0,0 @@ -CFBundleDocumentTypes - - - CFBundleTypeIconFile - Document - CFBundleTypeRole - Editor - LSHandlerRank - Alternate - LSItemContentTypes - - public.text - public.plain-text - public.utf8-plain-text - - - - CFBundleTypeIconFile - Document - CFBundleTypeName - Zed Text Document - CFBundleTypeRole - Editor - CFBundleTypeOSTypes - - **** - - LSHandlerRank - Default - CFBundleTypeExtensions - - Gemfile - c - c++ - cc - cpp - css - erb - ex - exs - go - h - h++ - hh - hpp - html - js - json - jsx - md - py - rb - rkt - rs - scm - toml - ts - tsx - txt - - - diff --git a/crates/zed2/resources/info/Permissions.plist b/crates/zed2/resources/info/Permissions.plist deleted file mode 100644 index bded5a82e2..0000000000 --- a/crates/zed2/resources/info/Permissions.plist +++ /dev/null @@ -1,24 +0,0 @@ -NSSystemAdministrationUsageDescription -The operation being performed by a program in Zed requires elevated permission. -NSAppleEventsUsageDescription -An application in Zed wants to use AppleScript. -NSBluetoothAlwaysUsageDescription -An application in Zed wants to use Bluetooth. -NSCalendarsUsageDescription -An application in Zed wants to use Calendar data. -NSCameraUsageDescription -An application in Zed wants to use the camera. -NSContactsUsageDescription -An application in Zed wants to use your contacts. -NSLocationAlwaysUsageDescription -An application in Zed wants to use your location information, even in the background. -NSLocationUsageDescription -An application in Zed wants to use your location information. -NSLocationWhenInUseUsageDescription -An application in Zed wants to use your location information while active. -NSMicrophoneUsageDescription -An application in Zed wants to use your microphone. -NSSpeechRecognitionUsageDescription -An application in Zed wants to use speech recognition. -NSRemindersUsageDescription -An application in Zed wants to use your reminders. diff --git a/crates/zed2/resources/zed.entitlements b/crates/zed2/resources/zed.entitlements deleted file mode 100644 index f40a8a253a..0000000000 --- a/crates/zed2/resources/zed.entitlements +++ /dev/null @@ -1,24 +0,0 @@ - - - - - com.apple.security.automation.apple-events - - com.apple.security.cs.allow-jit - - com.apple.security.device.audio-input - - com.apple.security.device.camera - - com.apple.security.personal-information.addressbook - - com.apple.security.personal-information.calendars - - com.apple.security.personal-information.location - - com.apple.security.personal-information.photos-library - - - - diff --git a/crates/zed2/src/assets.rs b/crates/zed2/src/assets.rs deleted file mode 100644 index 5d5e81a60e..0000000000 --- a/crates/zed2/src/assets.rs +++ /dev/null @@ -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> { - Self::get(path) - .map(|f| f.data) - .ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path)) - } - - fn list(&self, path: &str) -> Result> { - Ok(Self::iter() - .filter_map(|p| { - if p.starts_with(path) { - Some(p.into()) - } else { - None - } - }) - .collect()) - } -} diff --git a/crates/zed2/src/languages.rs b/crates/zed2/src/languages.rs deleted file mode 100644 index 3fdcad46fe..0000000000 --- a/crates/zed2/src/languages.rs +++ /dev/null @@ -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, - node_runtime: Arc, - 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], - ); - 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 { - 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> { - 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::(path.as_ref()); - match &mut result { - None => result = Some(contents), - Some(r) => r.to_mut().push_str(contents.as_ref()), - } - } - } - } - result -} diff --git a/crates/zed2/src/languages/bash/brackets.scm b/crates/zed2/src/languages/bash/brackets.scm deleted file mode 100644 index 191fd9c084..0000000000 --- a/crates/zed2/src/languages/bash/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) diff --git a/crates/zed2/src/languages/bash/config.toml b/crates/zed2/src/languages/bash/config.toml deleted file mode 100644 index 8c4513b250..0000000000 --- a/crates/zed2/src/languages/bash/config.toml +++ /dev/null @@ -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"] }, -] diff --git a/crates/zed2/src/languages/bash/highlights.scm b/crates/zed2/src/languages/bash/highlights.scm deleted file mode 100644 index 5cb5dad6a0..0000000000 --- a/crates/zed2/src/languages/bash/highlights.scm +++ /dev/null @@ -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 "^-") -) diff --git a/crates/zed2/src/languages/c.rs b/crates/zed2/src/languages/c.rs deleted file mode 100644 index a0b00d7797..0000000000 --- a/crates/zed2/src/languages/c.rs +++ /dev/null @@ -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> { - 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, - container_dir: PathBuf, - delegate: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_server_binary(container_dir).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - 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, - ) -> Option { - 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, - ) -> Option { - 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 { - (|| 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::(|store, cx| { - store.update_user_settings::(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 - }); - } -} diff --git a/crates/zed2/src/languages/c/brackets.scm b/crates/zed2/src/languages/c/brackets.scm deleted file mode 100644 index 9e8c9cd93c..0000000000 --- a/crates/zed2/src/languages/c/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("[" @open "]" @close) -("{" @open "}" @close) -("\"" @open "\"" @close) diff --git a/crates/zed2/src/languages/c/config.toml b/crates/zed2/src/languages/c/config.toml deleted file mode 100644 index f986f4b834..0000000000 --- a/crates/zed2/src/languages/c/config.toml +++ /dev/null @@ -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"] }, -] diff --git a/crates/zed2/src/languages/c/embedding.scm b/crates/zed2/src/languages/c/embedding.scm deleted file mode 100644 index 0178abeb18..0000000000 --- a/crates/zed2/src/languages/c/embedding.scm +++ /dev/null @@ -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 - ) diff --git a/crates/zed2/src/languages/c/highlights.scm b/crates/zed2/src/languages/c/highlights.scm deleted file mode 100644 index 064ec61a37..0000000000 --- a/crates/zed2/src/languages/c/highlights.scm +++ /dev/null @@ -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 - diff --git a/crates/zed2/src/languages/c/indents.scm b/crates/zed2/src/languages/c/indents.scm deleted file mode 100644 index fa40ce215e..0000000000 --- a/crates/zed2/src/languages/c/indents.scm +++ /dev/null @@ -1,9 +0,0 @@ -[ - (field_expression) - (assignment_expression) - (if_statement) - (for_statement) -] @indent - -(_ "{" "}" @end) @indent -(_ "(" ")" @end) @indent diff --git a/crates/zed2/src/languages/c/injections.scm b/crates/zed2/src/languages/c/injections.scm deleted file mode 100644 index 845a63bd1b..0000000000 --- a/crates/zed2/src/languages/c/injections.scm +++ /dev/null @@ -1,7 +0,0 @@ -(preproc_def - value: (preproc_arg) @content - (#set! "language" "c")) - -(preproc_function_def - value: (preproc_arg) @content - (#set! "language" "c")) \ No newline at end of file diff --git a/crates/zed2/src/languages/c/outline.scm b/crates/zed2/src/languages/c/outline.scm deleted file mode 100644 index ef80b7af8c..0000000000 --- a/crates/zed2/src/languages/c/outline.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/c/overrides.scm b/crates/zed2/src/languages/c/overrides.scm deleted file mode 100644 index 178355c67c..0000000000 --- a/crates/zed2/src/languages/c/overrides.scm +++ /dev/null @@ -1,2 +0,0 @@ -(comment) @comment -(string_literal) @string diff --git a/crates/zed2/src/languages/cpp/brackets.scm b/crates/zed2/src/languages/cpp/brackets.scm deleted file mode 100644 index 9e8c9cd93c..0000000000 --- a/crates/zed2/src/languages/cpp/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("[" @open "]" @close) -("{" @open "}" @close) -("\"" @open "\"" @close) diff --git a/crates/zed2/src/languages/cpp/config.toml b/crates/zed2/src/languages/cpp/config.toml deleted file mode 100644 index d9b38bca06..0000000000 --- a/crates/zed2/src/languages/cpp/config.toml +++ /dev/null @@ -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"] }, -] diff --git a/crates/zed2/src/languages/cpp/embedding.scm b/crates/zed2/src/languages/cpp/embedding.scm deleted file mode 100644 index bbd93f20db..0000000000 --- a/crates/zed2/src/languages/cpp/embedding.scm +++ /dev/null @@ -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 -) diff --git a/crates/zed2/src/languages/cpp/highlights.scm b/crates/zed2/src/languages/cpp/highlights.scm deleted file mode 100644 index bcfa01ca5c..0000000000 --- a/crates/zed2/src/languages/cpp/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/cpp/indents.scm b/crates/zed2/src/languages/cpp/indents.scm deleted file mode 100644 index a17f4c4821..0000000000 --- a/crates/zed2/src/languages/cpp/indents.scm +++ /dev/null @@ -1,7 +0,0 @@ -[ - (field_expression) - (assignment_expression) -] @indent - -(_ "{" "}" @end) @indent -(_ "(" ")" @end) @indent diff --git a/crates/zed2/src/languages/cpp/injections.scm b/crates/zed2/src/languages/cpp/injections.scm deleted file mode 100644 index eca372d577..0000000000 --- a/crates/zed2/src/languages/cpp/injections.scm +++ /dev/null @@ -1,7 +0,0 @@ -(preproc_def - value: (preproc_arg) @content - (#set! "language" "c++")) - -(preproc_function_def - value: (preproc_arg) @content - (#set! "language" "c++")) \ No newline at end of file diff --git a/crates/zed2/src/languages/cpp/outline.scm b/crates/zed2/src/languages/cpp/outline.scm deleted file mode 100644 index 38e75f193f..0000000000 --- a/crates/zed2/src/languages/cpp/outline.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/cpp/overrides.scm b/crates/zed2/src/languages/cpp/overrides.scm deleted file mode 100644 index 178355c67c..0000000000 --- a/crates/zed2/src/languages/cpp/overrides.scm +++ /dev/null @@ -1,2 +0,0 @@ -(comment) @comment -(string_literal) @string diff --git a/crates/zed2/src/languages/css.rs b/crates/zed2/src/languages/css.rs deleted file mode 100644 index fdbc179209..0000000000 --- a/crates/zed2/src/languages/css.rs +++ /dev/null @@ -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 { - vec![server_path.into(), "--stdio".into()] -} - -pub struct CssLspAdapter { - node: Arc, -} - -impl CssLspAdapter { - pub fn new(node: Arc) -> 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> { - Ok(Box::new( - self.node - .npm_package_latest_version("vscode-langservers-extracted") - .await?, - ) as Box<_>) - } - - async fn fetch_server_binary( - &self, - version: Box, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn initialization_options(&self) -> Option { - Some(json!({ - "provideFormatter": true - })) - } -} - -async fn get_cached_server_binary( - container_dir: PathBuf, - node: &dyn NodeRuntime, -) -> Option { - (|| 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() -} diff --git a/crates/zed2/src/languages/css/brackets.scm b/crates/zed2/src/languages/css/brackets.scm deleted file mode 100644 index 191fd9c084..0000000000 --- a/crates/zed2/src/languages/css/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) diff --git a/crates/zed2/src/languages/css/config.toml b/crates/zed2/src/languages/css/config.toml deleted file mode 100644 index 24a844c239..0000000000 --- a/crates/zed2/src/languages/css/config.toml +++ /dev/null @@ -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" diff --git a/crates/zed2/src/languages/css/highlights.scm b/crates/zed2/src/languages/css/highlights.scm deleted file mode 100644 index e271d8583c..0000000000 --- a/crates/zed2/src/languages/css/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/css/indents.scm b/crates/zed2/src/languages/css/indents.scm deleted file mode 100644 index e975469092..0000000000 --- a/crates/zed2/src/languages/css/indents.scm +++ /dev/null @@ -1 +0,0 @@ -(_ "{" "}" @end) @indent diff --git a/crates/zed2/src/languages/css/overrides.scm b/crates/zed2/src/languages/css/overrides.scm deleted file mode 100644 index c0db9fe327..0000000000 --- a/crates/zed2/src/languages/css/overrides.scm +++ /dev/null @@ -1,2 +0,0 @@ -(comment) @comment -(string_value) @string diff --git a/crates/zed2/src/languages/elixir.rs b/crates/zed2/src/languages/elixir.rs deleted file mode 100644 index 90352c78b4..0000000000 --- a/crates/zed2/src/languages/elixir.rs +++ /dev/null @@ -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, - }, -} - -#[derive(Clone, Serialize, Default, Deserialize, JsonSchema)] -pub struct ElixirSettingsContent { - lsp: Option, -} - -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 - 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, - cx: &mut AsyncAppContext, - ) -> Option>> { - 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> { - 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, - container_dir: PathBuf, - delegate: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_server_binary_elixir_ls(container_dir).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - get_cached_server_binary_elixir_ls(container_dir).await - } - - async fn label_for_completion( - &self, - completion: &lsp::CompletionItem, - language: &Arc, - ) -> Option { - 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, - ) -> Option { - 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 { - 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> { - 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, - container_dir: PathBuf, - delegate: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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, - ::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 { - 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 { - 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, - ) -> Option { - label_for_completion_elixir(completion, language) - } - - async fn label_for_symbol( - &self, - name: &str, - symbol_kind: SymbolKind, - language: &Arc, - ) -> Option { - label_for_symbol_elixir(name, symbol_kind, language) - } -} - -async fn get_cached_server_binary_next(container_dir: PathBuf) -> Option { - 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, -} - -#[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> { - Ok(Box::new(()) as Box<_>) - } - - async fn fetch_server_binary( - &self, - _: Box, - _: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - 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 { - 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 { - 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, - ) -> Option { - label_for_completion_elixir(completion, language) - } - - async fn label_for_symbol( - &self, - name: &str, - symbol: SymbolKind, - language: &Arc, - ) -> Option { - label_for_symbol_elixir(name, symbol, language) - } -} - -fn label_for_completion_elixir( - completion: &lsp::CompletionItem, - language: &Arc, -) -> Option { - 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, -) -> Option { - Some(CodeLabel { - runs: language.highlight_text(&name.into(), 0..name.len()), - text: name.to_string(), - filter_range: 0..name.len(), - }) -} diff --git a/crates/zed2/src/languages/elixir/brackets.scm b/crates/zed2/src/languages/elixir/brackets.scm deleted file mode 100644 index d8713187e2..0000000000 --- a/crates/zed2/src/languages/elixir/brackets.scm +++ /dev/null @@ -1,5 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) -("\"" @open "\"" @close) -("do" @open "end" @close) diff --git a/crates/zed2/src/languages/elixir/config.toml b/crates/zed2/src/languages/elixir/config.toml deleted file mode 100644 index 8983c0e49b..0000000000 --- a/crates/zed2/src/languages/elixir/config.toml +++ /dev/null @@ -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"] diff --git a/crates/zed2/src/languages/elixir/embedding.scm b/crates/zed2/src/languages/elixir/embedding.scm deleted file mode 100644 index 16ad20746d..0000000000 --- a/crates/zed2/src/languages/elixir/embedding.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/elixir/highlights.scm b/crates/zed2/src/languages/elixir/highlights.scm deleted file mode 100644 index 0e779d195c..0000000000 --- a/crates/zed2/src/languages/elixir/highlights.scm +++ /dev/null @@ -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")) diff --git a/crates/zed2/src/languages/elixir/indents.scm b/crates/zed2/src/languages/elixir/indents.scm deleted file mode 100644 index ab6fc4da67..0000000000 --- a/crates/zed2/src/languages/elixir/indents.scm +++ /dev/null @@ -1,6 +0,0 @@ -(call) @indent - -(_ "[" "]" @end) @indent -(_ "{" "}" @end) @indent -(_ "(" ")" @end) @indent -(_ "do" "end" @end) @indent diff --git a/crates/zed2/src/languages/elixir/injections.scm b/crates/zed2/src/languages/elixir/injections.scm deleted file mode 100644 index 4de229f104..0000000000 --- a/crates/zed2/src/languages/elixir/injections.scm +++ /dev/null @@ -1,7 +0,0 @@ -; Phoenix HTML template - -((sigil - (sigil_name) @_sigil_name - (quoted_content) @content) - (#eq? @_sigil_name "H") - (#set! language "heex")) diff --git a/crates/zed2/src/languages/elixir/outline.scm b/crates/zed2/src/languages/elixir/outline.scm deleted file mode 100644 index a3311fb6d4..0000000000 --- a/crates/zed2/src/languages/elixir/outline.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/elixir/overrides.scm b/crates/zed2/src/languages/elixir/overrides.scm deleted file mode 100644 index 1812540181..0000000000 --- a/crates/zed2/src/languages/elixir/overrides.scm +++ /dev/null @@ -1,2 +0,0 @@ -(comment) @comment -[(string) (charlist)] @string diff --git a/crates/zed2/src/languages/elm/config.toml b/crates/zed2/src/languages/elm/config.toml deleted file mode 100644 index 5051427a93..0000000000 --- a/crates/zed2/src/languages/elm/config.toml +++ /dev/null @@ -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"] }, -] diff --git a/crates/zed2/src/languages/elm/highlights.scm b/crates/zed2/src/languages/elm/highlights.scm deleted file mode 100644 index 5723c7eecb..0000000000 --- a/crates/zed2/src/languages/elm/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/elm/injections.scm b/crates/zed2/src/languages/elm/injections.scm deleted file mode 100644 index 0567320675..0000000000 --- a/crates/zed2/src/languages/elm/injections.scm +++ /dev/null @@ -1,2 +0,0 @@ -((glsl_content) @content - (#set! "language" "glsl")) diff --git a/crates/zed2/src/languages/elm/outline.scm b/crates/zed2/src/languages/elm/outline.scm deleted file mode 100644 index 1d7d5a70b0..0000000000 --- a/crates/zed2/src/languages/elm/outline.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/erb/config.toml b/crates/zed2/src/languages/erb/config.toml deleted file mode 100644 index ebc45e9984..0000000000 --- a/crates/zed2/src/languages/erb/config.toml +++ /dev/null @@ -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"] diff --git a/crates/zed2/src/languages/erb/highlights.scm b/crates/zed2/src/languages/erb/highlights.scm deleted file mode 100644 index 0bf76a7d49..0000000000 --- a/crates/zed2/src/languages/erb/highlights.scm +++ /dev/null @@ -1,12 +0,0 @@ -(comment_directive) @comment - -[ - "<%#" - "<%" - "<%=" - "<%_" - "<%-" - "%>" - "-%>" - "_%>" -] @keyword diff --git a/crates/zed2/src/languages/erb/injections.scm b/crates/zed2/src/languages/erb/injections.scm deleted file mode 100644 index 7a69a818ef..0000000000 --- a/crates/zed2/src/languages/erb/injections.scm +++ /dev/null @@ -1,7 +0,0 @@ -((code) @content - (#set! "language" "ruby") - (#set! "combined")) - -((content) @content - (#set! "language" "html") - (#set! "combined")) diff --git a/crates/zed2/src/languages/glsl/config.toml b/crates/zed2/src/languages/glsl/config.toml deleted file mode 100644 index 4081a6381f..0000000000 --- a/crates/zed2/src/languages/glsl/config.toml +++ /dev/null @@ -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 }, -] diff --git a/crates/zed2/src/languages/glsl/highlights.scm b/crates/zed2/src/languages/glsl/highlights.scm deleted file mode 100644 index e4503c6fbb..0000000000 --- a/crates/zed2/src/languages/glsl/highlights.scm +++ /dev/null @@ -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_") -) diff --git a/crates/zed2/src/languages/go.rs b/crates/zed2/src/languages/go.rs deleted file mode 100644 index 0daf1527c3..0000000000 --- a/crates/zed2/src/languages/go.rs +++ /dev/null @@ -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 { - 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> { - let release = latest_github_release("golang/tools", false, delegate.http_client()).await?; - let version: Option = 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, - cx: &mut AsyncAppContext, - ) -> Option>> { - 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, - container_dir: PathBuf, - delegate: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::>().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 { - get_cached_server_binary(container_dir).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - 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, - ) -> Option { - 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, - ) -> Option { - 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 { - (|| 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, HighlightId)>, -) -> Vec<(Range, 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)], - }) - ); - } -} diff --git a/crates/zed2/src/languages/go/brackets.scm b/crates/zed2/src/languages/go/brackets.scm deleted file mode 100644 index 9e8c9cd93c..0000000000 --- a/crates/zed2/src/languages/go/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("[" @open "]" @close) -("{" @open "}" @close) -("\"" @open "\"" @close) diff --git a/crates/zed2/src/languages/go/config.toml b/crates/zed2/src/languages/go/config.toml deleted file mode 100644 index 1951e193f0..0000000000 --- a/crates/zed2/src/languages/go/config.toml +++ /dev/null @@ -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"] }, -] diff --git a/crates/zed2/src/languages/go/embedding.scm b/crates/zed2/src/languages/go/embedding.scm deleted file mode 100644 index 9d8700cdfb..0000000000 --- a/crates/zed2/src/languages/go/embedding.scm +++ /dev/null @@ -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 -) diff --git a/crates/zed2/src/languages/go/highlights.scm b/crates/zed2/src/languages/go/highlights.scm deleted file mode 100644 index 6a9be8aae0..0000000000 --- a/crates/zed2/src/languages/go/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/go/indents.scm b/crates/zed2/src/languages/go/indents.scm deleted file mode 100644 index abbb72eb37..0000000000 --- a/crates/zed2/src/languages/go/indents.scm +++ /dev/null @@ -1,9 +0,0 @@ -[ - (assignment_statement) - (call_expression) - (selector_expression) -] @indent - -(_ "[" "]" @end) @indent -(_ "{" "}" @end) @indent -(_ "(" ")" @end) @indent diff --git a/crates/zed2/src/languages/go/outline.scm b/crates/zed2/src/languages/go/outline.scm deleted file mode 100644 index 2ff7ef25a0..0000000000 --- a/crates/zed2/src/languages/go/outline.scm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/crates/zed2/src/languages/go/overrides.scm b/crates/zed2/src/languages/go/overrides.scm deleted file mode 100644 index 9eb287df3f..0000000000 --- a/crates/zed2/src/languages/go/overrides.scm +++ /dev/null @@ -1,6 +0,0 @@ -(comment) @comment -[ - (interpreted_string_literal) - (raw_string_literal) - (rune_literal) -] @string diff --git a/crates/zed2/src/languages/heex/config.toml b/crates/zed2/src/languages/heex/config.toml deleted file mode 100644 index 74cb5ac9ff..0000000000 --- a/crates/zed2/src/languages/heex/config.toml +++ /dev/null @@ -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"] diff --git a/crates/zed2/src/languages/heex/highlights.scm b/crates/zed2/src/languages/heex/highlights.scm deleted file mode 100644 index 5252b71fac..0000000000 --- a/crates/zed2/src/languages/heex/highlights.scm +++ /dev/null @@ -1,57 +0,0 @@ -; HEEx delimiters -[ - "/>" - "" - "{" - "}" -] @punctuation.bracket - -[ - "<%!--" - "<%" - "<%#" - "<%%=" - "<%=" - "%>" - "--%>" - "-->" - ""] -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" diff --git a/crates/zed2/src/languages/html/highlights.scm b/crates/zed2/src/languages/html/highlights.scm deleted file mode 100644 index 0ce535fad4..0000000000 --- a/crates/zed2/src/languages/html/highlights.scm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/crates/zed2/src/languages/html/indents.scm b/crates/zed2/src/languages/html/indents.scm deleted file mode 100644 index 436663dba3..0000000000 --- a/crates/zed2/src/languages/html/indents.scm +++ /dev/null @@ -1,6 +0,0 @@ -(start_tag ">" @end) @indent -(self_closing_tag "/>" @end) @indent - -(element - (start_tag) @start - (end_tag)? @end) @indent diff --git a/crates/zed2/src/languages/html/injections.scm b/crates/zed2/src/languages/html/injections.scm deleted file mode 100644 index 9084e373f2..0000000000 --- a/crates/zed2/src/languages/html/injections.scm +++ /dev/null @@ -1,7 +0,0 @@ -(script_element - (raw_text) @content - (#set! "language" "javascript")) - -(style_element - (raw_text) @content - (#set! "language" "css")) diff --git a/crates/zed2/src/languages/html/outline.scm b/crates/zed2/src/languages/html/outline.scm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/zed2/src/languages/html/overrides.scm b/crates/zed2/src/languages/html/overrides.scm deleted file mode 100644 index 97accffd67..0000000000 --- a/crates/zed2/src/languages/html/overrides.scm +++ /dev/null @@ -1,2 +0,0 @@ -(comment) @comment -(quoted_attribute_value) @string \ No newline at end of file diff --git a/crates/zed2/src/languages/javascript/brackets.scm b/crates/zed2/src/languages/javascript/brackets.scm deleted file mode 100644 index 63395f81d8..0000000000 --- a/crates/zed2/src/languages/javascript/brackets.scm +++ /dev/null @@ -1,5 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) -("<" @open ">" @close) -("\"" @open "\"" @close) diff --git a/crates/zed2/src/languages/javascript/config.toml b/crates/zed2/src/languages/javascript/config.toml deleted file mode 100644 index 3b8862e358..0000000000 --- a/crates/zed2/src/languages/javascript/config.toml +++ /dev/null @@ -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"] diff --git a/crates/zed2/src/languages/javascript/contexts.scm b/crates/zed2/src/languages/javascript/contexts.scm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/zed2/src/languages/javascript/embedding.scm b/crates/zed2/src/languages/javascript/embedding.scm deleted file mode 100644 index ab1a3b6b06..0000000000 --- a/crates/zed2/src/languages/javascript/embedding.scm +++ /dev/null @@ -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 -) diff --git a/crates/zed2/src/languages/javascript/highlights.scm b/crates/zed2/src/languages/javascript/highlights.scm deleted file mode 100644 index 36ab21ca1e..0000000000 --- a/crates/zed2/src/languages/javascript/highlights.scm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/crates/zed2/src/languages/javascript/indents.scm b/crates/zed2/src/languages/javascript/indents.scm deleted file mode 100644 index 107e6ff8e0..0000000000 --- a/crates/zed2/src/languages/javascript/indents.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/javascript/outline.scm b/crates/zed2/src/languages/javascript/outline.scm deleted file mode 100644 index a1d4d339e8..0000000000 --- a/crates/zed2/src/languages/javascript/outline.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/javascript/overrides.scm b/crates/zed2/src/languages/javascript/overrides.scm deleted file mode 100644 index eb0a33b067..0000000000 --- a/crates/zed2/src/languages/javascript/overrides.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/json.rs b/crates/zed2/src/languages/json.rs deleted file mode 100644 index 162d4c9fdb..0000000000 --- a/crates/zed2/src/languages/json.rs +++ /dev/null @@ -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 { - vec![server_path.into(), "--stdio".into()] -} - -pub struct JsonLspAdapter { - node: Arc, - languages: Arc, -} - -impl JsonLspAdapter { - pub fn new(node: Arc, languages: Arc) -> 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> { - Ok(Box::new( - self.node - .npm_package_latest_version("vscode-json-languageserver") - .await?, - ) as Box<_>) - } - - async fn fetch_server_binary( - &self, - version: Box, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn initialization_options(&self) -> Option { - 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::().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 { - [("JSON".into(), "jsonc".into())].into_iter().collect() - } -} - -async fn get_cached_server_binary( - container_dir: PathBuf, - node: &dyn NodeRuntime, -) -> Option { - (|| 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() -} diff --git a/crates/zed2/src/languages/json/brackets.scm b/crates/zed2/src/languages/json/brackets.scm deleted file mode 100644 index 9e8c9cd93c..0000000000 --- a/crates/zed2/src/languages/json/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("[" @open "]" @close) -("{" @open "}" @close) -("\"" @open "\"" @close) diff --git a/crates/zed2/src/languages/json/config.toml b/crates/zed2/src/languages/json/config.toml deleted file mode 100644 index 37a6d3a54c..0000000000 --- a/crates/zed2/src/languages/json/config.toml +++ /dev/null @@ -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" diff --git a/crates/zed2/src/languages/json/embedding.scm b/crates/zed2/src/languages/json/embedding.scm deleted file mode 100644 index fa286e3880..0000000000 --- a/crates/zed2/src/languages/json/embedding.scm +++ /dev/null @@ -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) diff --git a/crates/zed2/src/languages/json/highlights.scm b/crates/zed2/src/languages/json/highlights.scm deleted file mode 100644 index b5c64e9634..0000000000 --- a/crates/zed2/src/languages/json/highlights.scm +++ /dev/null @@ -1,21 +0,0 @@ -(comment) @comment - -(string) @string - -(pair - key: (string) @property) - -(number) @number - -[ - (true) - (false) - (null) -] @constant - -[ - "{" - "}" - "[" - "]" -] @punctuation.bracket \ No newline at end of file diff --git a/crates/zed2/src/languages/json/indents.scm b/crates/zed2/src/languages/json/indents.scm deleted file mode 100644 index b7b2a2e767..0000000000 --- a/crates/zed2/src/languages/json/indents.scm +++ /dev/null @@ -1,2 +0,0 @@ -(array "]" @end) @indent -(object "}" @end) @indent diff --git a/crates/zed2/src/languages/json/outline.scm b/crates/zed2/src/languages/json/outline.scm deleted file mode 100644 index 43e2743478..0000000000 --- a/crates/zed2/src/languages/json/outline.scm +++ /dev/null @@ -1,2 +0,0 @@ -(pair - key: (string (string_content) @name)) @item diff --git a/crates/zed2/src/languages/json/overrides.scm b/crates/zed2/src/languages/json/overrides.scm deleted file mode 100644 index 746dbc5cd9..0000000000 --- a/crates/zed2/src/languages/json/overrides.scm +++ /dev/null @@ -1 +0,0 @@ -(string) @string \ No newline at end of file diff --git a/crates/zed2/src/languages/language_plugin.rs b/crates/zed2/src/languages/language_plugin.rs deleted file mode 100644 index 968cc819fd..0000000000 --- a/crates/zed2/src/languages/language_plugin.rs +++ /dev/null @@ -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) -> Result { - 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>, - fetch_server_binary: WasiFn<(PathBuf, String), Result>, - cached_server_binary: WasiFn>, - initialization_options: WasiFn<(), String>, - language_ids: WasiFn<(), Vec<(String, String)>>, - executor: Arc, - runtime: Arc>, -} - -impl PluginLspAdapter { - #[allow(unused)] - pub async fn new(mut plugin: Plugin, executor: Arc) -> Result { - 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> { - 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> = - runtime.call::<_, Option>(&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, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - let version = *version.downcast::().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 = - 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 { - 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 = - 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 { - None - } - - async fn initialization_options(&self) -> Option { - 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 { - self.runtime - .lock() - .await - .call(&self.language_ids, ()) - .await - .log_err() - .unwrap_or_default() - .into_iter() - .collect() - } -} diff --git a/crates/zed2/src/languages/lua.rs b/crates/zed2/src/languages/lua.rs deleted file mode 100644 index 5fffb37e81..0000000000 --- a/crates/zed2/src/languages/lua.rs +++ /dev/null @@ -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> { - 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, - container_dir: PathBuf, - delegate: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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, - ::from_mode(0o755), - ) - .await?; - Ok(LanguageServerBinary { - path: binary_path, - arguments: Vec::new(), - }) - } - - async fn cached_server_binary( - &self, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Option { - get_cached_server_binary(container_dir).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - 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 { - 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() -} diff --git a/crates/zed2/src/languages/lua/brackets.scm b/crates/zed2/src/languages/lua/brackets.scm deleted file mode 100644 index 5f5bd60b93..0000000000 --- a/crates/zed2/src/languages/lua/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("[" @open "]" @close) -("{" @open "}" @close) -("(" @open ")" @close) \ No newline at end of file diff --git a/crates/zed2/src/languages/lua/config.toml b/crates/zed2/src/languages/lua/config.toml deleted file mode 100644 index d3e44edfe9..0000000000 --- a/crates/zed2/src/languages/lua/config.toml +++ /dev/null @@ -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 = "--[ ... ]--" diff --git a/crates/zed2/src/languages/lua/embedding.scm b/crates/zed2/src/languages/lua/embedding.scm deleted file mode 100644 index 0d1065089f..0000000000 --- a/crates/zed2/src/languages/lua/embedding.scm +++ /dev/null @@ -1,10 +0,0 @@ -( - (comment)* @context - . - (function_declaration - "function" @name - name: (_) @name - (comment)* @collapse - body: (block) @collapse - ) @item -) diff --git a/crates/zed2/src/languages/lua/highlights.scm b/crates/zed2/src/languages/lua/highlights.scm deleted file mode 100644 index f061bbf8f9..0000000000 --- a/crates/zed2/src/languages/lua/highlights.scm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/crates/zed2/src/languages/lua/indents.scm b/crates/zed2/src/languages/lua/indents.scm deleted file mode 100644 index 71e15a0c33..0000000000 --- a/crates/zed2/src/languages/lua/indents.scm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/crates/zed2/src/languages/lua/outline.scm b/crates/zed2/src/languages/lua/outline.scm deleted file mode 100644 index 8bd8d88070..0000000000 --- a/crates/zed2/src/languages/lua/outline.scm +++ /dev/null @@ -1,3 +0,0 @@ -(function_declaration - "function" @context - name: (_) @name) @item \ No newline at end of file diff --git a/crates/zed2/src/languages/markdown/config.toml b/crates/zed2/src/languages/markdown/config.toml deleted file mode 100644 index 2fa3ff3cf2..0000000000 --- a/crates/zed2/src/languages/markdown/config.toml +++ /dev/null @@ -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 }, -] diff --git a/crates/zed2/src/languages/markdown/highlights.scm b/crates/zed2/src/languages/markdown/highlights.scm deleted file mode 100644 index 971c276868..0000000000 --- a/crates/zed2/src/languages/markdown/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/markdown/injections.scm b/crates/zed2/src/languages/markdown/injections.scm deleted file mode 100644 index 577054b404..0000000000 --- a/crates/zed2/src/languages/markdown/injections.scm +++ /dev/null @@ -1,4 +0,0 @@ -(fenced_code_block - (info_string - (language) @language) - (code_fence_content) @content) diff --git a/crates/zed2/src/languages/nix/config.toml b/crates/zed2/src/languages/nix/config.toml deleted file mode 100644 index 778f0a6f05..0000000000 --- a/crates/zed2/src/languages/nix/config.toml +++ /dev/null @@ -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 }, -] diff --git a/crates/zed2/src/languages/nix/highlights.scm b/crates/zed2/src/languages/nix/highlights.scm deleted file mode 100644 index d63a46411a..0000000000 --- a/crates/zed2/src/languages/nix/highlights.scm +++ /dev/null @@ -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 - (#match? @function.builtin "^(__add|__addErrorContext|__all|__any|__appendContext|__attrNames|__attrValues|__bitAnd|__bitOr|__bitXor|__catAttrs|__compareVersions|__concatLists|__concatMap|__concatStringsSep|__deepSeq|__div|__elem|__elemAt|__fetchurl|__filter|__filterSource|__findFile|__foldl'|__fromJSON|__functionArgs|__genList|__genericClosure|__getAttr|__getContext|__getEnv|__hasAttr|__hasContext|__hashFile|__hashString|__head|__intersectAttrs|__isAttrs|__isBool|__isFloat|__isFunction|__isInt|__isList|__isPath|__isString|__langVersion|__length|__lessThan|__listToAttrs|__mapAttrs|__match|__mul|__parseDrvName|__partition|__path|__pathExists|__readDir|__readFile|__replaceStrings|__seq|__sort|__split|__splitVersion|__storePath|__stringLength|__sub|__substring|__tail|__toFile|__toJSON|__toPath|__toXML|__trace|__tryEval|__typeOf|__unsafeDiscardOutputDependency|__unsafeDiscardStringContext|__unsafeGetAttrPos|__valueSize|abort|baseNameOf|derivation|derivationStrict|dirOf|fetchGit|fetchMercurial|fetchTarball|fromTOML|import|isNull|map|placeholder|removeAttrs|scopedImport|throw|toString)$") - (#is-not? local)) - -((identifier) @variable.builtin - (#match? @variable.builtin "^(__currentSystem|__currentTime|__nixPath|__nixVersion|__storeDir|builtins|false|null|true)$") - (#is-not? local)) diff --git a/crates/zed2/src/languages/nu.rs b/crates/zed2/src/languages/nu.rs deleted file mode 100644 index a3631b8471..0000000000 --- a/crates/zed2/src/languages/nu.rs +++ /dev/null @@ -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> { - Ok(Box::new(())) - } - - async fn fetch_server_binary( - &self, - _version: Box, - _container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - 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 { - Some(LanguageServerBinary { - path: "nu".into(), - arguments: vec!["--lsp".into()], - }) - } - - fn can_be_reinstalled(&self) -> bool { - false - } - - async fn installation_test_binary(&self, _: PathBuf) -> Option { - None - } -} diff --git a/crates/zed2/src/languages/nu/brackets.scm b/crates/zed2/src/languages/nu/brackets.scm deleted file mode 100644 index 7ede7a6192..0000000000 --- a/crates/zed2/src/languages/nu/brackets.scm +++ /dev/null @@ -1,4 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) -(parameter_pipes "|" @open "|" @close) diff --git a/crates/zed2/src/languages/nu/config.toml b/crates/zed2/src/languages/nu/config.toml deleted file mode 100644 index d382b0705a..0000000000 --- a/crates/zed2/src/languages/nu/config.toml +++ /dev/null @@ -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 }, -] diff --git a/crates/zed2/src/languages/nu/highlights.scm b/crates/zed2/src/languages/nu/highlights.scm deleted file mode 100644 index 97f46d3879..0000000000 --- a/crates/zed2/src/languages/nu/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/nu/indents.scm b/crates/zed2/src/languages/nu/indents.scm deleted file mode 100644 index 112b414aa4..0000000000 --- a/crates/zed2/src/languages/nu/indents.scm +++ /dev/null @@ -1,3 +0,0 @@ -(_ "[" "]" @end) @indent -(_ "{" "}" @end) @indent -(_ "(" ")" @end) @indent diff --git a/crates/zed2/src/languages/php.rs b/crates/zed2/src/languages/php.rs deleted file mode 100644 index e3d0f1c690..0000000000 --- a/crates/zed2/src/languages/php.rs +++ /dev/null @@ -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 { - vec![server_path.into(), "--stdio".into()] -} - -pub struct IntelephenseVersion(String); - -pub struct IntelephenseLspAdapter { - node: Arc, -} - -impl IntelephenseLspAdapter { - const SERVER_PATH: &'static str = "node_modules/intelephense/lib/intelephense.js"; - - pub fn new(node: Arc) -> 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> { - Ok(Box::new(IntelephenseVersion( - self.node.npm_package_latest_version("intelephense").await?, - )) as Box<_>) - } - - async fn fetch_server_binary( - &self, - version: Box, - container_dir: PathBuf, - _delegate: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn label_for_completion( - &self, - _item: &lsp::CompletionItem, - _language: &Arc, - ) -> Option { - None - } - - async fn initialization_options(&self) -> Option { - None - } - async fn language_ids(&self) -> HashMap { - HashMap::from_iter([("PHP".into(), "php".into())]) - } -} - -async fn get_cached_server_binary( - container_dir: PathBuf, - node: &dyn NodeRuntime, -) -> Option { - (|| 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() -} diff --git a/crates/zed2/src/languages/php/config.toml b/crates/zed2/src/languages/php/config.toml deleted file mode 100644 index f5ad67c12d..0000000000 --- a/crates/zed2/src/languages/php/config.toml +++ /dev/null @@ -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"] diff --git a/crates/zed2/src/languages/php/embedding.scm b/crates/zed2/src/languages/php/embedding.scm deleted file mode 100644 index db277775b3..0000000000 --- a/crates/zed2/src/languages/php/embedding.scm +++ /dev/null @@ -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 - ) diff --git a/crates/zed2/src/languages/php/highlights.scm b/crates/zed2/src/languages/php/highlights.scm deleted file mode 100644 index fcb087c47d..0000000000 --- a/crates/zed2/src/languages/php/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/php/injections.scm b/crates/zed2/src/languages/php/injections.scm deleted file mode 100644 index 57abd8ea2b..0000000000 --- a/crates/zed2/src/languages/php/injections.scm +++ /dev/null @@ -1,3 +0,0 @@ -((text) @content - (#set! "language" "html") - (#set! "combined")) diff --git a/crates/zed2/src/languages/php/outline.scm b/crates/zed2/src/languages/php/outline.scm deleted file mode 100644 index 87986f1032..0000000000 --- a/crates/zed2/src/languages/php/outline.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/php/tags.scm b/crates/zed2/src/languages/php/tags.scm deleted file mode 100644 index 66d594c254..0000000000 --- a/crates/zed2/src/languages/php/tags.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/python.rs b/crates/zed2/src/languages/python.rs deleted file mode 100644 index d28cd9f6e4..0000000000 --- a/crates/zed2/src/languages/python.rs +++ /dev/null @@ -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 { - vec![server_path.into(), "--stdio".into()] -} - -pub struct PythonLspAdapter { - node: Arc, -} - -impl PythonLspAdapter { - pub fn new(node: Arc) -> 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> { - Ok(Box::new(self.node.npm_package_latest_version("pyright").await?) as Box<_>) - } - - async fn fetch_server_binary( - &self, - version: Box, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - 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, - ) -> Option { - 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, - ) -> Option { - 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 { - 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::(|store, cx| { - store.update_user_settings::(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| { - 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 - }); - } -} diff --git a/crates/zed2/src/languages/python/brackets.scm b/crates/zed2/src/languages/python/brackets.scm deleted file mode 100644 index 191fd9c084..0000000000 --- a/crates/zed2/src/languages/python/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) diff --git a/crates/zed2/src/languages/python/config.toml b/crates/zed2/src/languages/python/config.toml deleted file mode 100644 index 6777f6e60d..0000000000 --- a/crates/zed2/src/languages/python/config.toml +++ /dev/null @@ -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.*:" diff --git a/crates/zed2/src/languages/python/embedding.scm b/crates/zed2/src/languages/python/embedding.scm deleted file mode 100644 index e3efb3dbf6..0000000000 --- a/crates/zed2/src/languages/python/embedding.scm +++ /dev/null @@ -1,9 +0,0 @@ -(class_definition - "class" @context - name: (identifier) @name - ) @item - -(function_definition - "async"? @context - "def" @context - name: (_) @name) @item diff --git a/crates/zed2/src/languages/python/highlights.scm b/crates/zed2/src/languages/python/highlights.scm deleted file mode 100644 index 71ab963d82..0000000000 --- a/crates/zed2/src/languages/python/highlights.scm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/crates/zed2/src/languages/python/indents.scm b/crates/zed2/src/languages/python/indents.scm deleted file mode 100644 index 112b414aa4..0000000000 --- a/crates/zed2/src/languages/python/indents.scm +++ /dev/null @@ -1,3 +0,0 @@ -(_ "[" "]" @end) @indent -(_ "{" "}" @end) @indent -(_ "(" ")" @end) @indent diff --git a/crates/zed2/src/languages/python/outline.scm b/crates/zed2/src/languages/python/outline.scm deleted file mode 100644 index e3efb3dbf6..0000000000 --- a/crates/zed2/src/languages/python/outline.scm +++ /dev/null @@ -1,9 +0,0 @@ -(class_definition - "class" @context - name: (identifier) @name - ) @item - -(function_definition - "async"? @context - "def" @context - name: (_) @name) @item diff --git a/crates/zed2/src/languages/python/overrides.scm b/crates/zed2/src/languages/python/overrides.scm deleted file mode 100644 index 8a58e304e5..0000000000 --- a/crates/zed2/src/languages/python/overrides.scm +++ /dev/null @@ -1,2 +0,0 @@ -(comment) @comment -(string) @string diff --git a/crates/zed2/src/languages/racket/brackets.scm b/crates/zed2/src/languages/racket/brackets.scm deleted file mode 100644 index 191fd9c084..0000000000 --- a/crates/zed2/src/languages/racket/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) diff --git a/crates/zed2/src/languages/racket/config.toml b/crates/zed2/src/languages/racket/config.toml deleted file mode 100644 index 0177e6ef6d..0000000000 --- a/crates/zed2/src/languages/racket/config.toml +++ /dev/null @@ -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 }, -] diff --git a/crates/zed2/src/languages/racket/highlights.scm b/crates/zed2/src/languages/racket/highlights.scm deleted file mode 100644 index 3caf1d88e9..0000000000 --- a/crates/zed2/src/languages/racket/highlights.scm +++ /dev/null @@ -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 - "^(unit-from-context|for/last|syntax-case|match-let\\*-values|define-for-syntax|define/subexpression-pos-prop|set-field!|class-field-accessor|invoke-unit|#%stratified-body|for\\*/and|for\\*/weak-set|flat-rec-contract|for\\*/stream|planet|for/mutable-seteqv|log-error|delay|#%declare|prop:dict/contract|->d|lib|override\\*|define-local-member-name|send-generic|for\\*/hasheq|define-syntax|submod|except|include-at/relative-to/reader|public\\*|define-member-name|define/public|let\\*|for/and|for\\*/first|for|delay/strict|define-values-for-export|==|match-define-values|for/weak-seteq|for\\*/async|for/stream|for/weak-seteqv|set!-values|lambda|for\\*/product|augment-final\\*|pubment\\*|command-line|contract|case|struct-field-index|contract-struct|unless|for/hasheq|for/seteqv|with-method|define-values-for-syntax|for-template|pubment|for\\*/list|syntax-case\\*|init-field|define-serializable-class|=>|for/foldr/derived|letrec-syntaxes|overment\\*|unquote-splicing|_|inherit-field|for\\*|stream-lazy|match-lambda\\*|contract-pos/neg-doubling|unit/c|match-define|for\\*/set|unit/s|nor|#%expression|class/c|this%|place/context|super-make-object|when|set!|parametric->/c|syntax-id-rules|include/reader|compound-unit|override-final|get-field|gen:dict|for\\*/seteqv|for\\*/hash|#%provide|combine-out|link|with-contract-continuation-mark|define-struct/derived|stream\\*|λ|rename-out|define-serializable-class\\*|augment|define/augment|let|define-signature-form|letrec-syntax|abstract|define-namespace-anchor|#%module-begin|#%top-interaction|for\\*/weak-seteqv|do|define/subexpression-pos-prop/name|absent|send/apply|with-handlers\\*|all-from-out|provide-signature-elements|gen:stream|define/override-final|for\\*/mutable-seteqv|rename|quasisyntax/loc|instantiate|for/list|extends|include-at/relative-to|mixin|define/pubment|#%plain-lambda|except-out|#%plain-module-begin|init|for\\*/last|relative-in|define-unit/new-import-export|->dm|member-name-key|nand|interface\\*|struct|define/override|else|define/augment-final|failure-cont|open|log-info|define/final-prop|all-defined-out|for/sum|for\\*/sum|recursive-contract|define|define-logger|match\\*|log-debug|rename-inner|->|struct/derived|unit|class\\*|prefix-out|any|define/overment|define-signature|match-letrec-values|let-syntaxes|for/mutable-set|define/match|cond|super-instantiate|define-contract-struct|import|hash/dc|define-custom-set-types|public-final|for/vector|for-label|prefix-in|for\\*/foldr/derived|define-unit-binding|object-contract|syntax-rules|augride|for\\*/mutable-seteq|quasisyntax|inner|for-syntax|overment|send/keyword-apply|generic|let\\*-values|->m|define-values|struct-copy|init-depend|struct/ctc|match-lambda|#%printing-module-begin|match\\*/derived|case->m|this|file|stream-cons|inspect|field|for/weak-set|struct\\*|gen:custom-write|thunk\\*|combine-in|unquote|for/lists|define/private|for\\*/foldr|define-unit/s|with-continuation-mark|begin|prefix|quote-syntax/prune|object/c|interface|match/derived|for/hasheqv|current-contract-region|define-compound-unit|override|define/public-final|recontract-out|let/cc|augride\\*|inherit|send|define-values/invoke-unit|for/mutable-seteq|#%datum|for/first|match-let\\*|invoke-unit/infer|define/contract|syntax/loc|for\\*/hasheqv|define-sequence-syntax|let/ec|for/product|for\\*/fold/derived|define-syntax-rule|lazy|unconstrained-domain->|augment-final|private|class|define-splicing-for-clause-syntax|for\\*/fold|prompt-tag/c|contract-out|match/values|public-final\\*|case-lambda|for/fold|unsyntax|for/set|begin0|#%require|time|public|define-struct|include|define-values/invoke-unit/infer|only-space-in|struct/c|only-meta-in|unit/new-import-export|place|begin-for-syntax|shared|inherit/super|quote|for/or|struct/contract|export|inherit/inner|struct-out|let-syntax|augment\\*|for\\*/vector|rename-in|match-let|define-unit|:do-in|~@|for\\*/weak-seteq|private\\*|and|except-in|log-fatal|gen:equal\\+hash|provide|require|thunk|invariant-assertion|define-match-expander|init-rest|->\\*|class/derived|super-new|for/fold/derived|for\\*/mutable-set|match-lambda\\*\\*|only|with-contract|~\\?|opt/c|let-values|delay/thread|->i|for/foldr|for-meta|only-in|send\\+|\\.\\.\\.|struct-guard/c|->\\*m|gen:set|struct/dc|define-syntaxes|if|parameterize|module\\*|module|send\\*|#%variable-reference|compound-unit/infer|#%plain-app|for/hash|contracted|case->|match|for\\*/lists|#%app|letrec-values|log-warning|super|define/augride|local-require|provide/contract|define-struct/contract|match-let-values|quote-syntax|for\\*/seteq|define-compound-unit/infer|parameterize\\*|values/drop|for/seteq|tag|stream|delay/idle|module\\+|define-custom-hash-types|cons/dc|define-module-boundary-contract|or|protect-out|define-opt/c|implies|letrec-syntaxes\\+values|for\\*/or|unsyntax-splicing|override-final\\*|for/async|parameterize-break|syntax|place\\*|for-space|quasiquote|with-handlers|delay/sync|define-unit-from-context|match-letrec|#%top|define-unit/contract|delay/name|new|field-bound\\?|letrec|class-field-mutator|with-syntax|flat-murec-contract|rename-super|local)$" - )) - -((symbol) @comment - (#match? @comment "^#[cC][iIsS]$")) diff --git a/crates/zed2/src/languages/racket/indents.scm b/crates/zed2/src/languages/racket/indents.scm deleted file mode 100644 index 9a1cbad161..0000000000 --- a/crates/zed2/src/languages/racket/indents.scm +++ /dev/null @@ -1,3 +0,0 @@ -(_ "[" "]") @indent -(_ "{" "}") @indent -(_ "(" ")") @indent diff --git a/crates/zed2/src/languages/racket/outline.scm b/crates/zed2/src/languages/racket/outline.scm deleted file mode 100644 index 604e052a63..0000000000 --- a/crates/zed2/src/languages/racket/outline.scm +++ /dev/null @@ -1,10 +0,0 @@ -(list - . - (symbol) @start-symbol @context - . - [ - (symbol) @name - (list . (symbol) @name) - ] - (#match? @start-symbol "^define") -) @item \ No newline at end of file diff --git a/crates/zed2/src/languages/ruby.rs b/crates/zed2/src/languages/ruby.rs deleted file mode 100644 index 3890b90dbd..0000000000 --- a/crates/zed2/src/languages/ruby.rs +++ /dev/null @@ -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> { - Ok(Box::new(())) - } - - async fn fetch_server_binary( - &self, - _version: Box, - _container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - Err(anyhow!("solargraph must be installed manually")) - } - - async fn cached_server_binary( - &self, - _: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Option { - Some(LanguageServerBinary { - path: "solargraph".into(), - arguments: vec!["stdio".into()], - }) - } - - fn can_be_reinstalled(&self) -> bool { - false - } - - async fn installation_test_binary(&self, _: PathBuf) -> Option { - None - } - - async fn label_for_completion( - &self, - item: &lsp::CompletionItem, - language: &Arc, - ) -> Option { - 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, - ) -> Option { - 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, - } - } -} diff --git a/crates/zed2/src/languages/ruby/brackets.scm b/crates/zed2/src/languages/ruby/brackets.scm deleted file mode 100644 index 957b20ecdb..0000000000 --- a/crates/zed2/src/languages/ruby/brackets.scm +++ /dev/null @@ -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) \ No newline at end of file diff --git a/crates/zed2/src/languages/ruby/config.toml b/crates/zed2/src/languages/ruby/config.toml deleted file mode 100644 index 6c8c615015..0000000000 --- a/crates/zed2/src/languages/ruby/config.toml +++ /dev/null @@ -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 = "# ..." diff --git a/crates/zed2/src/languages/ruby/embedding.scm b/crates/zed2/src/languages/ruby/embedding.scm deleted file mode 100644 index 7a101e6b09..0000000000 --- a/crates/zed2/src/languages/ruby/embedding.scm +++ /dev/null @@ -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 - ) diff --git a/crates/zed2/src/languages/ruby/highlights.scm b/crates/zed2/src/languages/ruby/highlights.scm deleted file mode 100644 index 2610cfa1cc..0000000000 --- a/crates/zed2/src/languages/ruby/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/ruby/indents.scm b/crates/zed2/src/languages/ruby/indents.scm deleted file mode 100644 index ac5175fa6f..0000000000 --- a/crates/zed2/src/languages/ruby/indents.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/ruby/outline.scm b/crates/zed2/src/languages/ruby/outline.scm deleted file mode 100644 index 0b36dabadb..0000000000 --- a/crates/zed2/src/languages/ruby/outline.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/ruby/overrides.scm b/crates/zed2/src/languages/ruby/overrides.scm deleted file mode 100644 index 8a58e304e5..0000000000 --- a/crates/zed2/src/languages/ruby/overrides.scm +++ /dev/null @@ -1,2 +0,0 @@ -(comment) @comment -(string) @string diff --git a/crates/zed2/src/languages/rust.rs b/crates/zed2/src/languages/rust.rs deleted file mode 100644 index 6f6ffa4188..0000000000 --- a/crates/zed2/src/languages/rust.rs +++ /dev/null @@ -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> { - 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, - container_dir: PathBuf, - delegate: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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, - ::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 { - get_cached_server_binary(container_dir).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - get_cached_server_binary(container_dir) - .await - .map(|mut binary| { - binary.arguments = vec!["--help".into()]; - binary - }) - } - - async fn disk_based_diagnostic_sources(&self) -> Vec { - vec!["rustc".into()] - } - - async fn disk_based_diagnostics_progress_token(&self) -> Option { - 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, - ) -> Option { - 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, - ) -> Option { - 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 { - (|| 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) -> Vec".to_string()), - ..Default::default() - }) - .await, - Some(CodeLabel { - text: "hello(&mut Option) -> Vec".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) -> Vec".to_string()), - ..Default::default() - }) - .await, - Some(CodeLabel { - text: "hello(&mut Option) -> Vec".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) -> Vec".to_string()), - ..Default::default() - }) - .await, - Some(CodeLabel { - text: "hello(&mut Option) -> Vec".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::(|store, cx| { - store.update_user_settings::(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 - }); - } -} diff --git a/crates/zed2/src/languages/rust/brackets.scm b/crates/zed2/src/languages/rust/brackets.scm deleted file mode 100644 index 0be534c48c..0000000000 --- a/crates/zed2/src/languages/rust/brackets.scm +++ /dev/null @@ -1,6 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) -("<" @open ">" @close) -("\"" @open "\"" @close) -(closure_parameters "|" @open "|" @close) \ No newline at end of file diff --git a/crates/zed2/src/languages/rust/config.toml b/crates/zed2/src/languages/rust/config.toml deleted file mode 100644 index 8216ba0a74..0000000000 --- a/crates/zed2/src/languages/rust/config.toml +++ /dev/null @@ -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 = " /* ... */ " diff --git a/crates/zed2/src/languages/rust/embedding.scm b/crates/zed2/src/languages/rust/embedding.scm deleted file mode 100644 index 286b1d1357..0000000000 --- a/crates/zed2/src/languages/rust/embedding.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/rust/highlights.scm b/crates/zed2/src/languages/rust/highlights.scm deleted file mode 100644 index 7240173a89..0000000000 --- a/crates/zed2/src/languages/rust/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/rust/indents.scm b/crates/zed2/src/languages/rust/indents.scm deleted file mode 100644 index 9ab6b02908..0000000000 --- a/crates/zed2/src/languages/rust/indents.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/rust/injections.scm b/crates/zed2/src/languages/rust/injections.scm deleted file mode 100644 index 57ebea8539..0000000000 --- a/crates/zed2/src/languages/rust/injections.scm +++ /dev/null @@ -1,7 +0,0 @@ -(macro_invocation - (token_tree) @content - (#set! "language" "rust")) - -(macro_rule - (token_tree) @content - (#set! "language" "rust")) \ No newline at end of file diff --git a/crates/zed2/src/languages/rust/outline.scm b/crates/zed2/src/languages/rust/outline.scm deleted file mode 100644 index 5c89087ac0..0000000000 --- a/crates/zed2/src/languages/rust/outline.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/rust/overrides.scm b/crates/zed2/src/languages/rust/overrides.scm deleted file mode 100644 index 216a395147..0000000000 --- a/crates/zed2/src/languages/rust/overrides.scm +++ /dev/null @@ -1,8 +0,0 @@ -[ - (string_literal) - (raw_string_literal) -] @string -[ - (line_comment) - (block_comment) -] @comment diff --git a/crates/zed2/src/languages/scheme/brackets.scm b/crates/zed2/src/languages/scheme/brackets.scm deleted file mode 100644 index 191fd9c084..0000000000 --- a/crates/zed2/src/languages/scheme/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) diff --git a/crates/zed2/src/languages/scheme/config.toml b/crates/zed2/src/languages/scheme/config.toml deleted file mode 100644 index 7b47698833..0000000000 --- a/crates/zed2/src/languages/scheme/config.toml +++ /dev/null @@ -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"] }, -] diff --git a/crates/zed2/src/languages/scheme/highlights.scm b/crates/zed2/src/languages/scheme/highlights.scm deleted file mode 100644 index 40ba61cd05..0000000000 --- a/crates/zed2/src/languages/scheme/highlights.scm +++ /dev/null @@ -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)$" - )) diff --git a/crates/zed2/src/languages/scheme/indents.scm b/crates/zed2/src/languages/scheme/indents.scm deleted file mode 100644 index 9a1cbad161..0000000000 --- a/crates/zed2/src/languages/scheme/indents.scm +++ /dev/null @@ -1,3 +0,0 @@ -(_ "[" "]") @indent -(_ "{" "}") @indent -(_ "(" ")") @indent diff --git a/crates/zed2/src/languages/scheme/outline.scm b/crates/zed2/src/languages/scheme/outline.scm deleted file mode 100644 index 604e052a63..0000000000 --- a/crates/zed2/src/languages/scheme/outline.scm +++ /dev/null @@ -1,10 +0,0 @@ -(list - . - (symbol) @start-symbol @context - . - [ - (symbol) @name - (list . (symbol) @name) - ] - (#match? @start-symbol "^define") -) @item \ No newline at end of file diff --git a/crates/zed2/src/languages/scheme/overrides.scm b/crates/zed2/src/languages/scheme/overrides.scm deleted file mode 100644 index 8c0d41b046..0000000000 --- a/crates/zed2/src/languages/scheme/overrides.scm +++ /dev/null @@ -1,6 +0,0 @@ -[ - (comment) - (block_comment) - (directive) -] @comment -(string) @string diff --git a/crates/zed2/src/languages/svelte.rs b/crates/zed2/src/languages/svelte.rs deleted file mode 100644 index 34dab81772..0000000000 --- a/crates/zed2/src/languages/svelte.rs +++ /dev/null @@ -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 { - vec![server_path.into(), "--stdio".into()] -} - -pub struct SvelteLspAdapter { - node: Arc, -} - -impl SvelteLspAdapter { - pub fn new(node: Arc) -> 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> { - Ok(Box::new( - self.node - .npm_package_latest_version("svelte-language-server") - .await?, - ) as Box<_>) - } - - async fn fetch_server_binary( - &self, - version: Box, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn initialization_options(&self) -> Option { - 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 { - (|| 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() -} diff --git a/crates/zed2/src/languages/svelte/config.toml b/crates/zed2/src/languages/svelte/config.toml deleted file mode 100644 index 76f03493b5..0000000000 --- a/crates/zed2/src/languages/svelte/config.toml +++ /dev/null @@ -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"] diff --git a/crates/zed2/src/languages/svelte/folds.scm b/crates/zed2/src/languages/svelte/folds.scm deleted file mode 100755 index 795c32fc4a..0000000000 --- a/crates/zed2/src/languages/svelte/folds.scm +++ /dev/null @@ -1,9 +0,0 @@ -[ - (style_element) - (script_element) - (element) - (if_statement) - (else_statement) - (each_statement) - (await_statement) -] @fold diff --git a/crates/zed2/src/languages/svelte/highlights.scm b/crates/zed2/src/languages/svelte/highlights.scm deleted file mode 100755 index de873684e4..0000000000 --- a/crates/zed2/src/languages/svelte/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/svelte/indents.scm b/crates/zed2/src/languages/svelte/indents.scm deleted file mode 100755 index 886d8ca867..0000000000 --- a/crates/zed2/src/languages/svelte/indents.scm +++ /dev/null @@ -1,8 +0,0 @@ -[ - (element) - (if_statement) - (each_statement) - (await_statement) - (script_element) - (style_element) -] @indent diff --git a/crates/zed2/src/languages/svelte/injections.scm b/crates/zed2/src/languages/svelte/injections.scm deleted file mode 100755 index 8c1ac9fcd0..0000000000 --- a/crates/zed2/src/languages/svelte/injections.scm +++ /dev/null @@ -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")) diff --git a/crates/zed2/src/languages/svelte/overrides.scm b/crates/zed2/src/languages/svelte/overrides.scm deleted file mode 100644 index 2a76410297..0000000000 --- a/crates/zed2/src/languages/svelte/overrides.scm +++ /dev/null @@ -1,7 +0,0 @@ -(comment) @comment - -[ - (raw_text) - (attribute_value) - (quoted_attribute_value) -] @string diff --git a/crates/zed2/src/languages/tailwind.rs b/crates/zed2/src/languages/tailwind.rs deleted file mode 100644 index 0dfa700b01..0000000000 --- a/crates/zed2/src/languages/tailwind.rs +++ /dev/null @@ -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 { - vec![server_path.into(), "--stdio".into()] -} - -pub struct TailwindLspAdapter { - node: Arc, -} - -impl TailwindLspAdapter { - pub fn new(node: Arc) -> 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> { - Ok(Box::new( - self.node - .npm_package_latest_version("@tailwindcss/language-server") - .await?, - ) as Box<_>) - } - - async fn fetch_server_binary( - &self, - version: Box, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn initialization_options(&self) -> Option { - 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 { - 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 { - (|| 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() -} diff --git a/crates/zed2/src/languages/toml/brackets.scm b/crates/zed2/src/languages/toml/brackets.scm deleted file mode 100644 index 9e8c9cd93c..0000000000 --- a/crates/zed2/src/languages/toml/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("[" @open "]" @close) -("{" @open "}" @close) -("\"" @open "\"" @close) diff --git a/crates/zed2/src/languages/toml/config.toml b/crates/zed2/src/languages/toml/config.toml deleted file mode 100644 index 188239a8e0..0000000000 --- a/crates/zed2/src/languages/toml/config.toml +++ /dev/null @@ -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"] }, -] diff --git a/crates/zed2/src/languages/toml/highlights.scm b/crates/zed2/src/languages/toml/highlights.scm deleted file mode 100644 index 04d83b5459..0000000000 --- a/crates/zed2/src/languages/toml/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/toml/indents.scm b/crates/zed2/src/languages/toml/indents.scm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/zed2/src/languages/toml/outline.scm b/crates/zed2/src/languages/toml/outline.scm deleted file mode 100644 index d232d489b6..0000000000 --- a/crates/zed2/src/languages/toml/outline.scm +++ /dev/null @@ -1,15 +0,0 @@ -(table - . - "[" - . - (_) @name) @item - -(table_array_element - . - "[[" - . - (_) @name) @item - -(pair - . - (_) @name) @item \ No newline at end of file diff --git a/crates/zed2/src/languages/toml/overrides.scm b/crates/zed2/src/languages/toml/overrides.scm deleted file mode 100644 index 8a58e304e5..0000000000 --- a/crates/zed2/src/languages/toml/overrides.scm +++ /dev/null @@ -1,2 +0,0 @@ -(comment) @comment -(string) @string diff --git a/crates/zed2/src/languages/tsx/brackets.scm b/crates/zed2/src/languages/tsx/brackets.scm deleted file mode 120000 index e6835c943b..0000000000 --- a/crates/zed2/src/languages/tsx/brackets.scm +++ /dev/null @@ -1 +0,0 @@ -../typescript/brackets.scm \ No newline at end of file diff --git a/crates/zed2/src/languages/tsx/config.toml b/crates/zed2/src/languages/tsx/config.toml deleted file mode 100644 index 0dae25d779..0000000000 --- a/crates/zed2/src/languages/tsx/config.toml +++ /dev/null @@ -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"] diff --git a/crates/zed2/src/languages/tsx/embedding.scm b/crates/zed2/src/languages/tsx/embedding.scm deleted file mode 100644 index ddcff66584..0000000000 --- a/crates/zed2/src/languages/tsx/embedding.scm +++ /dev/null @@ -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 - ) diff --git a/crates/zed2/src/languages/tsx/highlights-jsx.scm b/crates/zed2/src/languages/tsx/highlights-jsx.scm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/zed2/src/languages/tsx/highlights.scm b/crates/zed2/src/languages/tsx/highlights.scm deleted file mode 120000 index 226302a5d1..0000000000 --- a/crates/zed2/src/languages/tsx/highlights.scm +++ /dev/null @@ -1 +0,0 @@ -../typescript/highlights.scm \ No newline at end of file diff --git a/crates/zed2/src/languages/tsx/indents.scm b/crates/zed2/src/languages/tsx/indents.scm deleted file mode 120000 index 502c2a060a..0000000000 --- a/crates/zed2/src/languages/tsx/indents.scm +++ /dev/null @@ -1 +0,0 @@ -../typescript/indents.scm \ No newline at end of file diff --git a/crates/zed2/src/languages/tsx/outline.scm b/crates/zed2/src/languages/tsx/outline.scm deleted file mode 120000 index a0df409fda..0000000000 --- a/crates/zed2/src/languages/tsx/outline.scm +++ /dev/null @@ -1 +0,0 @@ -../typescript/outline.scm \ No newline at end of file diff --git a/crates/zed2/src/languages/tsx/overrides.scm b/crates/zed2/src/languages/tsx/overrides.scm deleted file mode 100644 index eb0a33b067..0000000000 --- a/crates/zed2/src/languages/tsx/overrides.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/typescript.rs b/crates/zed2/src/languages/typescript.rs deleted file mode 100644 index de25f2ead8..0000000000 --- a/crates/zed2/src/languages/typescript.rs +++ /dev/null @@ -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 { - vec![server_path.into(), "--stdio".into()] -} - -fn eslint_server_binary_arguments(server_path: &Path) -> Vec { - vec![server_path.into(), "--stdio".into()] -} - -pub struct TypeScriptLspAdapter { - node: Arc, -} - -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) -> 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> { - 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, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_ts_server_binary(container_dir, &*self.node).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - get_cached_ts_server_binary(container_dir, &*self.node).await - } - - fn code_action_kinds(&self) -> Option> { - Some(vec![ - CodeActionKind::QUICKFIX, - CodeActionKind::REFACTOR, - CodeActionKind::REFACTOR_EXTRACT, - CodeActionKind::SOURCE, - ]) - } - - async fn label_for_completion( - &self, - item: &lsp::CompletionItem, - language: &Arc, - ) -> Option { - 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 { - Some(json!({ - "provideFormatter": true, - "tsserver": { - "path": "node_modules/typescript/lib", - }, - })) - } - - async fn language_ids(&self) -> HashMap { - 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 { - (|| 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, -} - -impl EsLintLspAdapter { - const SERVER_PATH: &'static str = "vscode-eslint/server/out/eslintServer.js"; - - pub fn new(node: Arc) -> 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> { - // 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, - container_dir: PathBuf, - delegate: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_eslint_server_binary(container_dir, &*self.node).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - get_cached_eslint_server_binary(container_dir, &*self.node).await - } - - async fn label_for_completion( - &self, - _item: &lsp::CompletionItem, - _language: &Arc, - ) -> Option { - None - } - - async fn initialization_options(&self) -> Option { - None - } -} - -async fn get_cached_eslint_server_binary( - container_dir: PathBuf, - node: &dyn NodeRuntime, -) -> Option { - (|| 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::>(), - &[ - ("function a()", 0), - ("async function a2()", 1), - ("let b", 0), - ("function getB()", 0), - ("const d", 0), - ] - ); - } -} diff --git a/crates/zed2/src/languages/typescript/brackets.scm b/crates/zed2/src/languages/typescript/brackets.scm deleted file mode 100644 index 63395f81d8..0000000000 --- a/crates/zed2/src/languages/typescript/brackets.scm +++ /dev/null @@ -1,5 +0,0 @@ -("(" @open ")" @close) -("[" @open "]" @close) -("{" @open "}" @close) -("<" @open ">" @close) -("\"" @open "\"" @close) diff --git a/crates/zed2/src/languages/typescript/config.toml b/crates/zed2/src/languages/typescript/config.toml deleted file mode 100644 index d1ebffc559..0000000000 --- a/crates/zed2/src/languages/typescript/config.toml +++ /dev/null @@ -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" diff --git a/crates/zed2/src/languages/typescript/embedding.scm b/crates/zed2/src/languages/typescript/embedding.scm deleted file mode 100644 index 3170cb7c95..0000000000 --- a/crates/zed2/src/languages/typescript/embedding.scm +++ /dev/null @@ -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 -) diff --git a/crates/zed2/src/languages/typescript/highlights.scm b/crates/zed2/src/languages/typescript/highlights.scm deleted file mode 100644 index bf086ea156..0000000000 --- a/crates/zed2/src/languages/typescript/highlights.scm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/crates/zed2/src/languages/typescript/indents.scm b/crates/zed2/src/languages/typescript/indents.scm deleted file mode 100644 index 107e6ff8e0..0000000000 --- a/crates/zed2/src/languages/typescript/indents.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/typescript/outline.scm b/crates/zed2/src/languages/typescript/outline.scm deleted file mode 100644 index 68d297653e..0000000000 --- a/crates/zed2/src/languages/typescript/outline.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/typescript/overrides.scm b/crates/zed2/src/languages/typescript/overrides.scm deleted file mode 100644 index 8a58e304e5..0000000000 --- a/crates/zed2/src/languages/typescript/overrides.scm +++ /dev/null @@ -1,2 +0,0 @@ -(comment) @comment -(string) @string diff --git a/crates/zed2/src/languages/uiua.rs b/crates/zed2/src/languages/uiua.rs deleted file mode 100644 index 0efdfdd70d..0000000000 --- a/crates/zed2/src/languages/uiua.rs +++ /dev/null @@ -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> { - Ok(Box::new(())) - } - - async fn fetch_server_binary( - &self, - _version: Box, - _container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - Err(anyhow!( - "uiua must be installed and available in your $PATH" - )) - } - - async fn cached_server_binary( - &self, - _: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Option { - Some(LanguageServerBinary { - path: "uiua".into(), - arguments: vec!["lsp".into()], - }) - } - - fn can_be_reinstalled(&self) -> bool { - false - } - - async fn installation_test_binary(&self, _: PathBuf) -> Option { - None - } -} diff --git a/crates/zed2/src/languages/uiua/config.toml b/crates/zed2/src/languages/uiua/config.toml deleted file mode 100644 index 72fdc91040..0000000000 --- a/crates/zed2/src/languages/uiua/config.toml +++ /dev/null @@ -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"] }, -] diff --git a/crates/zed2/src/languages/uiua/highlights.scm b/crates/zed2/src/languages/uiua/highlights.scm deleted file mode 100644 index 2c37f404e6..0000000000 --- a/crates/zed2/src/languages/uiua/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/uiua/indents.scm b/crates/zed2/src/languages/uiua/indents.scm deleted file mode 100644 index add68c723c..0000000000 --- a/crates/zed2/src/languages/uiua/indents.scm +++ /dev/null @@ -1,3 +0,0 @@ -[ - (array) -] @indent diff --git a/crates/zed2/src/languages/vue.rs b/crates/zed2/src/languages/vue.rs deleted file mode 100644 index 16afd2e299..0000000000 --- a/crates/zed2/src/languages/vue.rs +++ /dev/null @@ -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, - typescript_install_path: Mutex>, -} - -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) -> 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> { - 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 { - 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> { - // 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, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - 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 { - 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, - ) -> Option { - 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 { - vec![server_path.into(), "--stdio".into()] -} - -type TypescriptPath = PathBuf; -async fn get_cached_server_binary( - container_dir: PathBuf, - node: Arc, -) -> 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() -} diff --git a/crates/zed2/src/languages/vue/brackets.scm b/crates/zed2/src/languages/vue/brackets.scm deleted file mode 100644 index 2d12b17daa..0000000000 --- a/crates/zed2/src/languages/vue/brackets.scm +++ /dev/null @@ -1,2 +0,0 @@ -("<" @open ">" @close) -("\"" @open "\"" @close) diff --git a/crates/zed2/src/languages/vue/config.toml b/crates/zed2/src/languages/vue/config.toml deleted file mode 100644 index c41a667b75..0000000000 --- a/crates/zed2/src/languages/vue/config.toml +++ /dev/null @@ -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 = ["-"] diff --git a/crates/zed2/src/languages/vue/highlights.scm b/crates/zed2/src/languages/vue/highlights.scm deleted file mode 100644 index 1a80c84f68..0000000000 --- a/crates/zed2/src/languages/vue/highlights.scm +++ /dev/null @@ -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 diff --git a/crates/zed2/src/languages/vue/injections.scm b/crates/zed2/src/languages/vue/injections.scm deleted file mode 100644 index 9084e373f2..0000000000 --- a/crates/zed2/src/languages/vue/injections.scm +++ /dev/null @@ -1,7 +0,0 @@ -(script_element - (raw_text) @content - (#set! "language" "javascript")) - -(style_element - (raw_text) @content - (#set! "language" "css")) diff --git a/crates/zed2/src/languages/yaml.rs b/crates/zed2/src/languages/yaml.rs deleted file mode 100644 index fbed9ba78f..0000000000 --- a/crates/zed2/src/languages/yaml.rs +++ /dev/null @@ -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 { - vec![server_path.into(), "--stdio".into()] -} - -pub struct YamlLspAdapter { - node: Arc, -} - -impl YamlLspAdapter { - pub fn new(node: Arc) -> 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> { - Ok(Box::new( - self.node - .npm_package_latest_version("yaml-language-server") - .await?, - ) as Box<_>) - } - - async fn fetch_server_binary( - &self, - version: Box, - container_dir: PathBuf, - _: &dyn LspAdapterDelegate, - ) -> Result { - let version = version.downcast::().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 { - get_cached_server_binary(container_dir, &*self.node).await - } - - async fn installation_test_binary( - &self, - container_dir: PathBuf, - ) -> Option { - 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 { - (|| 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() -} diff --git a/crates/zed2/src/languages/yaml/brackets.scm b/crates/zed2/src/languages/yaml/brackets.scm deleted file mode 100644 index 9e8c9cd93c..0000000000 --- a/crates/zed2/src/languages/yaml/brackets.scm +++ /dev/null @@ -1,3 +0,0 @@ -("[" @open "]" @close) -("{" @open "}" @close) -("\"" @open "\"" @close) diff --git a/crates/zed2/src/languages/yaml/config.toml b/crates/zed2/src/languages/yaml/config.toml deleted file mode 100644 index 4e91dd348b..0000000000 --- a/crates/zed2/src/languages/yaml/config.toml +++ /dev/null @@ -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" diff --git a/crates/zed2/src/languages/yaml/highlights.scm b/crates/zed2/src/languages/yaml/highlights.scm deleted file mode 100644 index 06081f63cb..0000000000 --- a/crates/zed2/src/languages/yaml/highlights.scm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/crates/zed2/src/languages/yaml/outline.scm b/crates/zed2/src/languages/yaml/outline.scm deleted file mode 100644 index e85eb1bf8a..0000000000 --- a/crates/zed2/src/languages/yaml/outline.scm +++ /dev/null @@ -1 +0,0 @@ -(block_mapping_pair key: (flow_node (plain_scalar (string_scalar) @name))) @item \ No newline at end of file diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs deleted file mode 100644 index 53c4855dc7..0000000000 --- a/crates/zed2/src/main.rs +++ /dev/null @@ -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::>() { - if let Some(app_state) = cx.global::>().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::({ - 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, - 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, 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, 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, - backtrace: Vec, - app_version: String, - release_channel: String, - os_name: String, - os_version: Option, - architecture: String, - panicked_on: i64, - #[serde(skip_serializing_if = "Option::is_none")] - installation_id: Option, - 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, 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(""); - - let payload = info - .payload() - .downcast_ref::<&str>() - .map(|s| s.to_string()) - .or_else(|| info.payload().downcast_ref::().map(|s| s.clone())) - .unwrap_or_else(|| "Box".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::>(); - - // 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, 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 { - 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, languages: Arc) -> 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, 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, _: Arc) -> Option<()> { - None -} - -#[cfg(not(debug_assertions))] -fn watch_file_types(_fs: Arc, _cx: &mut AppContext) {} diff --git a/crates/zed2/src/only_instance.rs b/crates/zed2/src/only_instance.rs deleted file mode 100644 index e950392d99..0000000000 --- a/crates/zed2/src/only_instance.rs +++ /dev/null @@ -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, - } -} diff --git a/crates/zed2/src/open_listener.rs b/crates/zed2/src/open_listener.rs deleted file mode 100644 index 6db020a785..0000000000 --- a/crates/zed2/src/open_listener.rs +++ /dev/null @@ -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, - }, - CliConnection { - connection: (mpsc::Receiver, IpcSender), - }, - JoinChannel { - channel_id: u64, - }, - OpenChannelNotes { - channel_id: u64, - }, -} - -pub struct OpenListener { - tx: UnboundedSender, - pub triggered: AtomicBool, -} - -impl OpenListener { - pub fn new() -> (Self, UnboundedReceiver) { - 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 { - 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 { - 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::() { - 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 { - 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, IpcSender)> { - let handshake_tx = cli::ipc::IpcSender::::connect(server_name.to_string()) - .context("error connecting to cli")?; - let (request_tx, request_rx) = ipc::channel::()?; - let (response_tx, response_rx) = ipc::channel::()?; - - 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::(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, IpcSender), - app_state: Arc, - 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::() { - 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(); - } - } - } -} diff --git a/crates/zed2/src/zed2.rs b/crates/zed2/src/zed2.rs deleted file mode 100644 index bcfdb848ab..0000000000 --- a/crates/zed2/src/zed2.rs +++ /dev/null @@ -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, - display_uuid: Option, - 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, 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::>() - .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::("licenses.md"), - "Open Source License Attribution", - "Markdown", - cx, - ); - }) - .register_action( - move |workspace: &mut Workspace, - _: &OpenTelemetryLog, - cx: &mut ViewContext| { - open_telemetry_log_file(workspace, cx); - }, - ) - .register_action( - move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext| { - create_and_open_local_file(&paths::KEYMAP, cx, Default::default) - .detach_and_log_err(cx); - }, - ) - .register_action( - move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext| { - 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| { - open_bundled_file( - workspace, - settings::default_keymap(), - "Default Key Bindings", - "JSON", - cx, - ); - }, - ) - .register_action( - move |workspace: &mut Workspace, - _: &OpenDefaultSettings, - cx: &mut ViewContext| { - open_bundled_file( - workspace, - settings::default_settings(), - "Default Settings", - "JSON", - cx, - ); - }, - ) - //todo!() - // cx.add_action({ - // move |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext| { - // 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.toggle_panel_focus::(cx); - // }, - // ); - // cx.add_action( - // |workspace: &mut Workspace, - // _: &collab_ui::collab_panel::ToggleFocus, - // cx: &mut ViewContext| { - // workspace.toggle_panel_focus::(cx); - // }, - // ); - // cx.add_action( - // |workspace: &mut Workspace, - // _: &collab_ui::chat_panel::ToggleFocus, - // cx: &mut ViewContext| { - // workspace.toggle_panel_focus::(cx); - // }, - // ); - // cx.add_action( - // |workspace: &mut Workspace, - // _: &collab_ui::notification_panel::ToggleFocus, - // cx: &mut ViewContext| { - // workspace.toggle_panel_focus::(cx); - // }, - // ); - // cx.add_action( - // |workspace: &mut Workspace, - // _: &terminal_panel::ToggleFocus, - // cx: &mut ViewContext| { - // workspace.toggle_panel_focus::(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, cx: &mut ViewContext) { - 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) { - use std::fmt::Write as _; - - let app_name = cx.global::().display_name(); - let version = env!("CARGO_PKG_VERSION"); - let mut message = format!("{app_name} {version}"); - if let Some(sha) = cx.try_global::() { - 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) { - 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::()) - .collect::>() - })?; - - // 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) { - 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::(); - - 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, - 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::(cx)); - // drop(settings_subscription); - // settings_subscription = Some(cx.update(|cx| { - // cx.observe_global::(move |cx| { - // let new_base_keymap = *settings::get::(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, -) { - 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::() - .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.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) -> Option { - 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, -) { - 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::().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::().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::().unwrap().root(cx); -// workspace_1.update(cx, |workspace, cx| { -// assert_eq!( -// workspace -// .worktrees(cx) -// .map(|w| w.read(cx).abs_path()) -// .collect::>(), -// &[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, 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::().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::() -// .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::() -// .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::() -// .unwrap(); -// let workspace = window.root(cx); - -// let editor = workspace.update(cx, |workspace, cx| { -// workspace -// .active_item(cx) -// .unwrap() -// .downcast::() -// .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::>(); -// 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::().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::(), -// workspace.right_dock().read(cx).panel::(), -// workspace.bottom_dock().read(cx).panel::(), -// ] -// .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::() -// .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::>(); -// 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::() -// .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::>(); -// 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::() -// .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::>(); -// 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::>(); -// 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::() -// .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::(|store, cx| { -// store.update_user_settings::(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::>() -// }); -// 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::>(); -// 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::().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::() -// .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::() -// .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::() -// .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::().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::().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::() -// .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::() -// .unwrap(); -// let editor3 = workspace -// .update(cx, |w, cx| w.open_path(file3.clone(), None, true, cx)) -// .await -// .unwrap() -// .downcast::() -// .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, -// cx: &mut TestAppContext, -// ) -> (ProjectPath, DisplayPoint, f32) { -// workspace.update(cx, |workspace, cx| { -// let item = workspace.active_item(cx).unwrap(); -// let editor = item.downcast::().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, -// cx: &TestAppContext, -// ) -> Option { -// 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) -> AnyElement { -// 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) -> AnyElement { -// 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::(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 { -// 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 { -// Arc::new(language::Language::new( -// language::LanguageConfig { -// name: "Rust".into(), -// path_suffixes: vec!["rs".to_string()], -// ..Default::default() -// }, -// Some(tree_sitter_rust::language()), -// )) -// } -// } diff --git a/docs/old/local-collaboration.md b/docs/old/local-collaboration.md index 4c059c0878..7bbbda3645 100644 --- a/docs/old/local-collaboration.md +++ b/docs/old/local-collaboration.md @@ -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. diff --git a/docs/src/developing_zed__local_collaboration.md b/docs/src/developing_zed__local_collaboration.md index 4c059c0878..7bbbda3645 100644 --- a/docs/src/developing_zed__local_collaboration.md +++ b/docs/src/developing_zed__local_collaboration.md @@ -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. diff --git a/script/bundle b/script/bundle index 95a789885f..4627066799 100755 --- a/script/bundle +++ b/script/bundle @@ -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 diff --git a/script/crate-dep-graph b/script/crate-dep-graph index 74ea36683c..256ef42343 100755 --- a/script/crate-dep-graph +++ b/script/crate-dep-graph @@ -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 diff --git a/script/zed-2-progress-report.py b/script/zed-2-progress-report.py deleted file mode 100644 index 87f7f7b8f7..0000000000 --- a/script/zed-2-progress-report.py +++ /dev/null @@ -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}%") diff --git a/script/zed-local b/script/zed-local index bb0f1bd5da..8ba1561bbd 100755 --- a/script/zed-local +++ b/script/zed-local @@ -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" });