Provide wasm extensions with APIs needed for using pre-installed LSP binaries (#9085)
In this PR, we've added two new methods that LSP extensions can call: * `shell_env()`, for retrieving the environment variables set in the user's default shell in the worktree * `which(command)`, for looking up paths to an executable (accounting for the user's shell env in the worktree) To test this out, we moved the `uiua` language support into an extension. We went ahead and removed the built-in support, since this language is extremely obscure. Sorry @mikayla-maki. To continue coding in Uiua in Zed, for now you can `Add Dev Extension` from the extensions pane, and select the `extensions/uiua` directory in the Zed repo. Very soon, we'll support publishing these extensions so that you'll be able to just install it normally. Release Notes: - N/A --------- Co-authored-by: Marshall <marshall@zed.dev>
This commit is contained in:
parent
5abcc1c3c5
commit
8a6264d933
23 changed files with 235 additions and 256 deletions
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
@ -89,9 +89,6 @@ jobs:
|
||||||
- name: cargo clippy
|
- name: cargo clippy
|
||||||
run: cargo xtask clippy
|
run: cargo xtask clippy
|
||||||
|
|
||||||
- name: Install WASI dependencies
|
|
||||||
run: script/setup-wasm
|
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
uses: ./.github/actions/run_tests
|
uses: ./.github/actions/run_tests
|
||||||
|
|
||||||
|
|
163
Cargo.lock
generated
163
Cargo.lock
generated
|
@ -3011,15 +3011,6 @@ dependencies = [
|
||||||
"util",
|
"util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "debugid"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
|
|
||||||
dependencies = [
|
|
||||||
"uuid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deflate"
|
name = "deflate"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
|
@ -3159,16 +3150,6 @@ dependencies = [
|
||||||
"subtle",
|
"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]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "3.0.2"
|
version = "3.0.2"
|
||||||
|
@ -3556,6 +3537,7 @@ dependencies = [
|
||||||
"theme",
|
"theme",
|
||||||
"toml 0.8.10",
|
"toml 0.8.10",
|
||||||
"util",
|
"util",
|
||||||
|
"wasm-encoder",
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
"wasmtime",
|
"wasmtime",
|
||||||
"wasmtime-wasi",
|
"wasmtime-wasi",
|
||||||
|
@ -4165,28 +4147,6 @@ dependencies = [
|
||||||
"thread_local",
|
"thread_local",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fxhash"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fxprof-processed-profile"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.2",
|
|
||||||
"debugid",
|
|
||||||
"fxhash",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.7"
|
||||||
|
@ -5060,26 +5020,6 @@ version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ittapi"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6b996fe614c41395cdaedf3cf408a9534851090959d90d54a535f675550b64b1"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"ittapi-sys",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ittapi-sys"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "52f5385394064fa2c886205dba02598013ce83d3e92d33dbdc0c52fe0e7bf4fc"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
version = "0.19.0"
|
version = "0.19.0"
|
||||||
|
@ -5385,7 +5325,6 @@ dependencies = [
|
||||||
"tree-sitter-svelte",
|
"tree-sitter-svelte",
|
||||||
"tree-sitter-toml",
|
"tree-sitter-toml",
|
||||||
"tree-sitter-typescript",
|
"tree-sitter-typescript",
|
||||||
"tree-sitter-uiua",
|
|
||||||
"tree-sitter-vue",
|
"tree-sitter-vue",
|
||||||
"tree-sitter-yaml",
|
"tree-sitter-yaml",
|
||||||
"tree-sitter-zig",
|
"tree-sitter-zig",
|
||||||
|
@ -10816,15 +10755,6 @@ dependencies = [
|
||||||
"tree-sitter",
|
"tree-sitter",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tree-sitter-uiua"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "git+https://github.com/shnarazk/tree-sitter-uiua?rev=21dc2db39494585bf29a3f86d5add6e9d11a22ba#21dc2db39494585bf29a3f86d5add6e9d11a22ba"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"tree-sitter",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tree-sitter-vue"
|
name = "tree-sitter-vue"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -11440,15 +11370,6 @@ dependencies = [
|
||||||
"leb128",
|
"leb128",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-encoder"
|
|
||||||
version = "0.201.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a"
|
|
||||||
dependencies = [
|
|
||||||
"leb128",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-metadata"
|
name = "wasm-metadata"
|
||||||
version = "0.10.20"
|
version = "0.10.20"
|
||||||
|
@ -11461,7 +11382,7 @@ dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"spdx",
|
"spdx",
|
||||||
"wasm-encoder 0.41.2",
|
"wasm-encoder",
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -11492,41 +11413,33 @@ version = "18.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c843b8bc4dd4f3a76173ba93405c71111d570af0d90ea5f6299c705d0c2add2"
|
checksum = "4c843b8bc4dd4f3a76173ba93405c71111d570af0d90ea5f6299c705d0c2add2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bincode",
|
"bincode",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"fxprof-processed-profile",
|
|
||||||
"gimli",
|
"gimli",
|
||||||
"indexmap 2.0.0",
|
"indexmap 2.0.0",
|
||||||
"ittapi",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"object",
|
"object",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"paste",
|
"paste",
|
||||||
"rayon",
|
|
||||||
"rustix 0.38.30",
|
"rustix 0.38.30",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"wasm-encoder 0.41.2",
|
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
"wasmtime-cache",
|
|
||||||
"wasmtime-component-macro",
|
"wasmtime-component-macro",
|
||||||
"wasmtime-component-util",
|
"wasmtime-component-util",
|
||||||
"wasmtime-cranelift",
|
"wasmtime-cranelift",
|
||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
"wasmtime-fiber",
|
"wasmtime-fiber",
|
||||||
"wasmtime-jit-debug",
|
|
||||||
"wasmtime-jit-icache-coherence",
|
"wasmtime-jit-icache-coherence",
|
||||||
"wasmtime-runtime",
|
"wasmtime-runtime",
|
||||||
"wasmtime-winch",
|
"wasmtime-winch",
|
||||||
"wat",
|
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -11563,26 +11476,6 @@ dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasmtime-cache"
|
|
||||||
version = "18.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6fb4fc2bbf9c790a57875eba65588fa97acf57a7d784dc86d057e648d9a1ed91"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"base64 0.21.4",
|
|
||||||
"bincode",
|
|
||||||
"directories-next",
|
|
||||||
"log",
|
|
||||||
"rustix 0.38.30",
|
|
||||||
"serde",
|
|
||||||
"serde_derive",
|
|
||||||
"sha2 0.10.7",
|
|
||||||
"toml 0.5.11",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
"zstd",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmtime-component-macro"
|
name = "wasmtime-component-macro"
|
||||||
version = "18.0.2"
|
version = "18.0.2"
|
||||||
|
@ -11664,7 +11557,7 @@ dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wasm-encoder 0.41.2",
|
"wasm-encoder",
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
"wasmprinter",
|
"wasmprinter",
|
||||||
"wasmtime-component-util",
|
"wasmtime-component-util",
|
||||||
|
@ -11686,18 +11579,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasmtime-jit-debug"
|
|
||||||
version = "18.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "833dae95bc7a4f9177bf93f9497419763535b74e37eb8c37be53937d3281e287"
|
|
||||||
dependencies = [
|
|
||||||
"object",
|
|
||||||
"once_cell",
|
|
||||||
"rustix 0.38.30",
|
|
||||||
"wasmtime-versioned-export-macros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmtime-jit-icache-coherence"
|
name = "wasmtime-jit-icache-coherence"
|
||||||
version = "18.0.2"
|
version = "18.0.2"
|
||||||
|
@ -11729,11 +11610,10 @@ dependencies = [
|
||||||
"psm",
|
"psm",
|
||||||
"rustix 0.38.30",
|
"rustix 0.38.30",
|
||||||
"sptr",
|
"sptr",
|
||||||
"wasm-encoder 0.41.2",
|
"wasm-encoder",
|
||||||
"wasmtime-asm-macros",
|
"wasmtime-asm-macros",
|
||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
"wasmtime-fiber",
|
"wasmtime-fiber",
|
||||||
"wasmtime-jit-debug",
|
|
||||||
"wasmtime-versioned-export-macros",
|
"wasmtime-versioned-export-macros",
|
||||||
"wasmtime-wmemcheck",
|
"wasmtime-wmemcheck",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
|
@ -11840,28 +11720,6 @@ dependencies = [
|
||||||
"leb128",
|
"leb128",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wast"
|
|
||||||
version = "201.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1ef6e1ef34d7da3e2b374fd2b1a9c0227aff6cad596e1b24df9b58d0f6222faa"
|
|
||||||
dependencies = [
|
|
||||||
"bumpalo",
|
|
||||||
"leb128",
|
|
||||||
"memchr",
|
|
||||||
"unicode-width",
|
|
||||||
"wasm-encoder 0.201.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wat"
|
|
||||||
version = "1.201.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "453d5b37a45b98dee4f4cb68015fc73634d7883bbef1c65e6e9c78d454cf3f32"
|
|
||||||
dependencies = [
|
|
||||||
"wast 201.0.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-backend"
|
name = "wayland-backend"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -12515,7 +12373,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"wasm-encoder 0.41.2",
|
"wasm-encoder",
|
||||||
"wasm-metadata",
|
"wasm-metadata",
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
"wit-parser 0.13.2",
|
"wit-parser 0.13.2",
|
||||||
|
@ -12534,7 +12392,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"wasm-encoder 0.41.2",
|
"wasm-encoder",
|
||||||
"wasm-metadata",
|
"wasm-metadata",
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
"wit-parser 0.14.0",
|
"wit-parser 0.14.0",
|
||||||
|
@ -12584,7 +12442,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"log",
|
"log",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wast 35.0.2",
|
"wast",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -13003,6 +12861,13 @@ dependencies = [
|
||||||
"zed_extension_api",
|
"zed_extension_api",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zed_uiua"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"zed_extension_api",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeno"
|
name = "zeno"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
|
|
@ -92,7 +92,10 @@ members = [
|
||||||
"crates/workspace",
|
"crates/workspace",
|
||||||
"crates/zed",
|
"crates/zed",
|
||||||
"crates/zed_actions",
|
"crates/zed_actions",
|
||||||
|
|
||||||
"extensions/gleam",
|
"extensions/gleam",
|
||||||
|
"extensions/uiua",
|
||||||
|
|
||||||
"tooling/xtask",
|
"tooling/xtask",
|
||||||
]
|
]
|
||||||
default-members = ["crates/zed"]
|
default-members = ["crates/zed"]
|
||||||
|
@ -308,7 +311,6 @@ tree-sitter-scheme = { git = "https://github.com/6cdh/tree-sitter-scheme", rev =
|
||||||
tree-sitter-svelte = { git = "https://github.com/Himujjal/tree-sitter-svelte", rev = "bd60db7d3d06f89b6ec3b287c9a6e9190b5564bd" }
|
tree-sitter-svelte = { git = "https://github.com/Himujjal/tree-sitter-svelte", rev = "bd60db7d3d06f89b6ec3b287c9a6e9190b5564bd" }
|
||||||
tree-sitter-toml = { git = "https://github.com/tree-sitter/tree-sitter-toml", rev = "342d9be207c2dba869b9967124c679b5e6fd0ebe" }
|
tree-sitter-toml = { git = "https://github.com/tree-sitter/tree-sitter-toml", rev = "342d9be207c2dba869b9967124c679b5e6fd0ebe" }
|
||||||
tree-sitter-typescript = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "5d20856f34315b068c41edaee2ac8a100081d259" }
|
tree-sitter-typescript = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "5d20856f34315b068c41edaee2ac8a100081d259" }
|
||||||
tree-sitter-uiua = { git = "https://github.com/shnarazk/tree-sitter-uiua", rev = "21dc2db39494585bf29a3f86d5add6e9d11a22ba" }
|
|
||||||
tree-sitter-vue = { git = "https://github.com/zed-industries/tree-sitter-vue", rev = "6608d9d60c386f19d80af7d8132322fa11199c42" }
|
tree-sitter-vue = { git = "https://github.com/zed-industries/tree-sitter-vue", rev = "6608d9d60c386f19d80af7d8132322fa11199c42" }
|
||||||
tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "f545a41f57502e1b5ddf2a6668896c1b0620f930" }
|
tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "f545a41f57502e1b5ddf2a6668896c1b0620f930" }
|
||||||
tree-sitter-zig = { git = "https://github.com/maxxnino/tree-sitter-zig", rev = "0d08703e4c3f426ec61695d7617415fff97029bd" }
|
tree-sitter-zig = { git = "https://github.com/maxxnino/tree-sitter-zig", rev = "0d08703e4c3f426ec61695d7617415fff97029bd" }
|
||||||
|
@ -317,7 +319,8 @@ unicase = "2.6"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
uuid = { version = "1.1.2", features = ["v4"] }
|
uuid = { version = "1.1.2", features = ["v4"] }
|
||||||
wasmparser = "0.121"
|
wasmparser = "0.121"
|
||||||
wasmtime = "18.0"
|
wasm-encoder = "0.41"
|
||||||
|
wasmtime = { version = "18.0", default-features = false, features = ["async", "demangle", "runtime", "cranelift", "component-model"] }
|
||||||
wasmtime-wasi = "18.0"
|
wasmtime-wasi = "18.0"
|
||||||
which = "6.0.0"
|
which = "6.0.0"
|
||||||
wit-component = "0.20"
|
wit-component = "0.20"
|
||||||
|
|
|
@ -37,7 +37,8 @@ settings.workspace = true
|
||||||
theme.workspace = true
|
theme.workspace = true
|
||||||
toml.workspace = true
|
toml.workspace = true
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
wasmtime = { workspace = true, features = ["async"] }
|
wasm-encoder.workspace = true
|
||||||
|
wasmtime.workspace = true
|
||||||
wasmtime-wasi.workspace = true
|
wasmtime-wasi.workspace = true
|
||||||
wasmparser.workspace = true
|
wasmparser.workspace = true
|
||||||
wit-component.workspace = true
|
wit-component.workspace = true
|
||||||
|
|
|
@ -6,13 +6,16 @@ use async_tar::Archive;
|
||||||
use futures::io::BufReader;
|
use futures::io::BufReader;
|
||||||
use futures::AsyncReadExt;
|
use futures::AsyncReadExt;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::mem;
|
||||||
use std::{
|
use std::{
|
||||||
env, fs,
|
env, fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use util::http::{AsyncBody, HttpClient};
|
use util::http::{self, AsyncBody, HttpClient};
|
||||||
|
use wasm_encoder::{ComponentSectionId, Encode as _, RawSection, Section as _};
|
||||||
|
use wasmparser::Parser;
|
||||||
use wit_component::ComponentEncoder;
|
use wit_component::ComponentEncoder;
|
||||||
|
|
||||||
/// Currently, we compile with Rust's `wasm32-wasi` target, which works with WASI `preview1`.
|
/// Currently, we compile with Rust's `wasm32-wasi` target, which works with WASI `preview1`.
|
||||||
|
@ -59,8 +62,11 @@ struct CargoTomlPackage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtensionBuilder {
|
impl ExtensionBuilder {
|
||||||
pub fn new(cache_dir: PathBuf, http: Arc<dyn HttpClient>) -> Self {
|
pub fn new(cache_dir: PathBuf) -> Self {
|
||||||
Self { cache_dir, http }
|
Self {
|
||||||
|
cache_dir,
|
||||||
|
http: http::client(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn compile_extension(
|
pub async fn compile_extension(
|
||||||
|
@ -138,6 +144,10 @@ impl ExtensionBuilder {
|
||||||
.encode()
|
.encode()
|
||||||
.context("failed to encode wasm component")?;
|
.context("failed to encode wasm component")?;
|
||||||
|
|
||||||
|
let component_bytes = self
|
||||||
|
.strip_custom_sections(&component_bytes)
|
||||||
|
.context("failed to strip debug sections from wasm component")?;
|
||||||
|
|
||||||
fs::write(extension_dir.join("extension.wasm"), &component_bytes)
|
fs::write(extension_dir.join("extension.wasm"), &component_bytes)
|
||||||
.context("failed to write extension.wasm")?;
|
.context("failed to write extension.wasm")?;
|
||||||
|
|
||||||
|
@ -310,7 +320,7 @@ impl ExtensionBuilder {
|
||||||
async fn install_wasi_preview1_adapter_if_needed(&self) -> Result<Vec<u8>> {
|
async fn install_wasi_preview1_adapter_if_needed(&self) -> Result<Vec<u8>> {
|
||||||
let cache_path = self.cache_dir.join("wasi_snapshot_preview1.reactor.wasm");
|
let cache_path = self.cache_dir.join("wasi_snapshot_preview1.reactor.wasm");
|
||||||
if let Ok(content) = fs::read(&cache_path) {
|
if let Ok(content) = fs::read(&cache_path) {
|
||||||
if wasmparser::Parser::is_core_wasm(&content) {
|
if Parser::is_core_wasm(&content) {
|
||||||
return Ok(content);
|
return Ok(content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,7 +343,7 @@ impl ExtensionBuilder {
|
||||||
fs::write(&cache_path, &content)
|
fs::write(&cache_path, &content)
|
||||||
.with_context(|| format!("failed to save file {}", cache_path.display()))?;
|
.with_context(|| format!("failed to save file {}", cache_path.display()))?;
|
||||||
|
|
||||||
if !wasmparser::Parser::is_core_wasm(&content) {
|
if !Parser::is_core_wasm(&content) {
|
||||||
bail!("downloaded wasi adapter is invalid");
|
bail!("downloaded wasi adapter is invalid");
|
||||||
}
|
}
|
||||||
Ok(content)
|
Ok(content)
|
||||||
|
@ -379,4 +389,68 @@ impl ExtensionBuilder {
|
||||||
|
|
||||||
Ok(clang_path)
|
Ok(clang_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This was adapted from:
|
||||||
|
// https://github.com/bytecodealliance/wasm-tools/1791a8f139722e9f8679a2bd3d8e423e55132b22/src/bin/wasm-tools/strip.rs
|
||||||
|
fn strip_custom_sections(&self, input: &Vec<u8>) -> Result<Vec<u8>> {
|
||||||
|
use wasmparser::Payload::*;
|
||||||
|
|
||||||
|
let strip_custom_section = |name: &str| name.starts_with(".debug");
|
||||||
|
|
||||||
|
let mut output = Vec::new();
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
|
for payload in Parser::new(0).parse_all(input) {
|
||||||
|
let payload = payload?;
|
||||||
|
|
||||||
|
// Track nesting depth, so that we don't mess with inner producer sections:
|
||||||
|
match payload {
|
||||||
|
Version { encoding, .. } => {
|
||||||
|
output.extend_from_slice(match encoding {
|
||||||
|
wasmparser::Encoding::Component => &wasm_encoder::Component::HEADER,
|
||||||
|
wasmparser::Encoding::Module => &wasm_encoder::Module::HEADER,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ModuleSection { .. } | ComponentSection { .. } => {
|
||||||
|
stack.push(mem::take(&mut output));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
End { .. } => {
|
||||||
|
let mut parent = match stack.pop() {
|
||||||
|
Some(c) => c,
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
if output.starts_with(&wasm_encoder::Component::HEADER) {
|
||||||
|
parent.push(ComponentSectionId::Component as u8);
|
||||||
|
output.encode(&mut parent);
|
||||||
|
} else {
|
||||||
|
parent.push(ComponentSectionId::CoreModule as u8);
|
||||||
|
output.encode(&mut parent);
|
||||||
|
}
|
||||||
|
output = parent;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match &payload {
|
||||||
|
CustomSection(c) => {
|
||||||
|
if strip_custom_section(c.name()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((id, range)) = payload.as_section() {
|
||||||
|
RawSection {
|
||||||
|
id,
|
||||||
|
data: &input[range],
|
||||||
|
}
|
||||||
|
.append_to(&mut output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,7 @@ impl ExtensionStore {
|
||||||
extension_index: Default::default(),
|
extension_index: Default::default(),
|
||||||
installed_dir,
|
installed_dir,
|
||||||
index_path,
|
index_path,
|
||||||
builder: Arc::new(ExtensionBuilder::new(build_dir, http_client.clone())),
|
builder: Arc::new(ExtensionBuilder::new(build_dir)),
|
||||||
outstanding_operations: Default::default(),
|
outstanding_operations: Default::default(),
|
||||||
modified_extensions: Default::default(),
|
modified_extensions: Default::default(),
|
||||||
reload_complete_senders: Vec::new(),
|
reload_complete_senders: Vec::new(),
|
||||||
|
@ -545,7 +545,7 @@ impl ExtensionStore {
|
||||||
builder
|
builder
|
||||||
.compile_extension(
|
.compile_extension(
|
||||||
&extension_source_path,
|
&extension_source_path,
|
||||||
CompileExtensionOptions { release: true },
|
CompileExtensionOptions { release: false },
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,7 @@ use collections::BTreeMap;
|
||||||
use fs::{FakeFs, Fs, RealFs};
|
use fs::{FakeFs, Fs, RealFs};
|
||||||
use futures::{io::BufReader, AsyncReadExt, StreamExt};
|
use futures::{io::BufReader, AsyncReadExt, StreamExt};
|
||||||
use gpui::{Context, TestAppContext};
|
use gpui::{Context, TestAppContext};
|
||||||
use language::{
|
use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName};
|
||||||
Language, LanguageConfig, LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus,
|
|
||||||
LanguageServerName,
|
|
||||||
};
|
|
||||||
use node_runtime::FakeNodeRuntime;
|
use node_runtime::FakeNodeRuntime;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use project::Project;
|
use project::Project;
|
||||||
|
@ -573,19 +570,6 @@ async fn test_extension_store_with_gleam_extension(cx: &mut TestAppContext) {
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
project.update(cx, |project, cx| {
|
|
||||||
project.set_language_for_buffer(
|
|
||||||
&buffer,
|
|
||||||
Arc::new(Language::new(
|
|
||||||
LanguageConfig {
|
|
||||||
name: "Gleam".into(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
)),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let fake_server = fake_servers.next().await.unwrap();
|
let fake_server = fake_servers.next().await.unwrap();
|
||||||
let expected_server_path = extensions_dir.join("work/gleam/gleam-v1.2.3/gleam");
|
let expected_server_path = extensions_dir.join("work/gleam/gleam-v1.2.3/gleam");
|
||||||
|
|
|
@ -3,7 +3,7 @@ use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
use async_compression::futures::bufread::GzipDecoder;
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
use async_tar::Archive;
|
use async_tar::Archive;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use fs::Fs;
|
use fs::{normalize_path, Fs};
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::{
|
channel::{
|
||||||
mpsc::{self, UnboundedSender},
|
mpsc::{self, UnboundedSender},
|
||||||
|
@ -72,8 +72,6 @@ type ExtensionCall = Box<
|
||||||
|
|
||||||
static WASM_ENGINE: OnceLock<wasmtime::Engine> = OnceLock::new();
|
static WASM_ENGINE: OnceLock<wasmtime::Engine> = OnceLock::new();
|
||||||
|
|
||||||
const EXTENSION_WORK_DIR_PATH: &str = "/zed/work";
|
|
||||||
|
|
||||||
impl WasmHost {
|
impl WasmHost {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
|
@ -181,11 +179,12 @@ impl WasmHost {
|
||||||
.await
|
.await
|
||||||
.context("failed to create extension work dir")?;
|
.context("failed to create extension work dir")?;
|
||||||
|
|
||||||
let work_dir_preopen = Dir::open_ambient_dir(extension_work_dir, ambient_authority())
|
let work_dir_preopen = Dir::open_ambient_dir(&extension_work_dir, ambient_authority())
|
||||||
.context("failed to preopen extension work directory")?;
|
.context("failed to preopen extension work directory")?;
|
||||||
let current_dir_preopen = work_dir_preopen
|
let current_dir_preopen = work_dir_preopen
|
||||||
.try_clone()
|
.try_clone()
|
||||||
.context("failed to preopen extension current directory")?;
|
.context("failed to preopen extension current directory")?;
|
||||||
|
let extension_work_dir = extension_work_dir.to_string_lossy();
|
||||||
|
|
||||||
let perms = wasi::FilePerms::all();
|
let perms = wasi::FilePerms::all();
|
||||||
let dir_perms = wasi::DirPerms::all();
|
let dir_perms = wasi::DirPerms::all();
|
||||||
|
@ -193,26 +192,24 @@ impl WasmHost {
|
||||||
Ok(wasi::WasiCtxBuilder::new()
|
Ok(wasi::WasiCtxBuilder::new()
|
||||||
.inherit_stdio()
|
.inherit_stdio()
|
||||||
.preopened_dir(current_dir_preopen, dir_perms, perms, ".")
|
.preopened_dir(current_dir_preopen, dir_perms, perms, ".")
|
||||||
.preopened_dir(work_dir_preopen, dir_perms, perms, EXTENSION_WORK_DIR_PATH)
|
.preopened_dir(work_dir_preopen, dir_perms, perms, &extension_work_dir)
|
||||||
.env("PWD", EXTENSION_WORK_DIR_PATH)
|
.env("PWD", &extension_work_dir)
|
||||||
.env("RUST_BACKTRACE", "1")
|
.env("RUST_BACKTRACE", "full")
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_from_extension(&self, id: &Arc<str>, path: &Path) -> PathBuf {
|
pub fn path_from_extension(&self, id: &Arc<str>, path: &Path) -> PathBuf {
|
||||||
self.writeable_path_from_extension(id, path)
|
let extension_work_dir = self.work_dir.join(id.as_ref());
|
||||||
.unwrap_or_else(|| path.to_path_buf())
|
normalize_path(&extension_work_dir.join(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeable_path_from_extension(&self, id: &Arc<str>, path: &Path) -> Option<PathBuf> {
|
pub fn writeable_path_from_extension(&self, id: &Arc<str>, path: &Path) -> Result<PathBuf> {
|
||||||
let path = path.strip_prefix(EXTENSION_WORK_DIR_PATH).unwrap_or(path);
|
let extension_work_dir = self.work_dir.join(id.as_ref());
|
||||||
if path.is_relative() {
|
let path = normalize_path(&extension_work_dir.join(path));
|
||||||
let mut result = self.work_dir.clone();
|
if path.starts_with(&extension_work_dir) {
|
||||||
result.push(id.as_ref());
|
Ok(path)
|
||||||
result.extend(path);
|
|
||||||
Some(result)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
Err(anyhow!("cannot write to path {}", path.display()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,13 +249,6 @@ impl WasmExtension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WasmState {
|
|
||||||
pub fn writeable_path_from_extension(&self, path: &Path) -> Option<PathBuf> {
|
|
||||||
self.host
|
|
||||||
.writeable_path_from_extension(&self.manifest.id, path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl wit::HostWorktree for WasmState {
|
impl wit::HostWorktree for WasmState {
|
||||||
async fn read_text_file(
|
async fn read_text_file(
|
||||||
|
@ -273,6 +263,26 @@ impl wit::HostWorktree for WasmState {
|
||||||
.map_err(|error| error.to_string()))
|
.map_err(|error| error.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn shell_env(
|
||||||
|
&mut self,
|
||||||
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
|
) -> wasmtime::Result<wit::EnvVars> {
|
||||||
|
let delegate = self.table.get(&delegate)?;
|
||||||
|
Ok(delegate.shell_env().await.into_iter().collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn which(
|
||||||
|
&mut self,
|
||||||
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
|
binary_name: String,
|
||||||
|
) -> wasmtime::Result<Option<String>> {
|
||||||
|
let delegate = self.table.get(&delegate)?;
|
||||||
|
Ok(delegate
|
||||||
|
.which(binary_name.as_ref())
|
||||||
|
.await
|
||||||
|
.map(|path| path.to_string_lossy().to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
fn drop(&mut self, _worktree: Resource<wit::Worktree>) -> Result<()> {
|
fn drop(&mut self, _worktree: Resource<wit::Worktree>) -> Result<()> {
|
||||||
// we only ever hand out borrows of worktrees
|
// we only ever hand out borrows of worktrees
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -395,8 +405,8 @@ impl wit::ExtensionImports for WasmState {
|
||||||
this.host.fs.create_dir(&extension_work_dir).await?;
|
this.host.fs.create_dir(&extension_work_dir).await?;
|
||||||
|
|
||||||
let destination_path = this
|
let destination_path = this
|
||||||
.writeable_path_from_extension(&path)
|
.host
|
||||||
.ok_or_else(|| anyhow!("cannot write to path {:?}", path))?;
|
.writeable_path_from_extension(&this.manifest.id, &path)?;
|
||||||
|
|
||||||
let mut response = this
|
let mut response = this
|
||||||
.host
|
.host
|
||||||
|
|
|
@ -61,14 +61,18 @@ world extension {
|
||||||
/// Updates the installation status for the given language server.
|
/// Updates the installation status for the given language server.
|
||||||
import set-language-server-installation-status: func(language-server-name: string, status: language-server-installation-status);
|
import set-language-server-installation-status: func(language-server-name: string, status: language-server-installation-status);
|
||||||
|
|
||||||
|
type env-vars = list<tuple<string, string>>;
|
||||||
|
|
||||||
record command {
|
record command {
|
||||||
command: string,
|
command: string,
|
||||||
args: list<string>,
|
args: list<string>,
|
||||||
env: list<tuple<string, string>>,
|
env: env-vars,
|
||||||
}
|
}
|
||||||
|
|
||||||
resource worktree {
|
resource worktree {
|
||||||
read-text-file: func(path: string) -> result<string, string>;
|
read-text-file: func(path: string) -> result<string, string>;
|
||||||
|
which: func(binary-name: string) -> option<string>;
|
||||||
|
shell-env: func() -> env-vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
record language-server-config {
|
record language-server-config {
|
||||||
|
|
|
@ -40,7 +40,7 @@ use smol::future::FutureExt as _;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
ffi::OsString,
|
ffi::OsStr,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
mem,
|
mem,
|
||||||
|
@ -277,7 +277,8 @@ pub trait LspAdapterDelegate: Send + Sync {
|
||||||
fn http_client(&self) -> Arc<dyn HttpClient>;
|
fn http_client(&self) -> Arc<dyn HttpClient>;
|
||||||
fn update_status(&self, language: LanguageServerName, status: LanguageServerBinaryStatus);
|
fn update_status(&self, language: LanguageServerName, status: LanguageServerBinaryStatus);
|
||||||
|
|
||||||
async fn which_command(&self, command: OsString) -> Option<(PathBuf, HashMap<String, String>)>;
|
async fn which(&self, command: &OsStr) -> Option<PathBuf>;
|
||||||
|
async fn shell_env(&self) -> HashMap<String, String>;
|
||||||
async fn read_text_file(&self, path: PathBuf) -> Result<String>;
|
async fn read_text_file(&self, path: PathBuf) -> Result<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,6 @@ tree-sitter-scheme.workspace = true
|
||||||
tree-sitter-svelte.workspace = true
|
tree-sitter-svelte.workspace = true
|
||||||
tree-sitter-toml.workspace = true
|
tree-sitter-toml.workspace = true
|
||||||
tree-sitter-typescript.workspace = true
|
tree-sitter-typescript.workspace = true
|
||||||
tree-sitter-uiua.workspace = true
|
|
||||||
tree-sitter-vue.workspace = true
|
tree-sitter-vue.workspace = true
|
||||||
tree-sitter-yaml.workspace = true
|
tree-sitter-yaml.workspace = true
|
||||||
tree-sitter-zig.workspace = true
|
tree-sitter-zig.workspace = true
|
||||||
|
|
|
@ -58,7 +58,8 @@ impl super::LspAdapter for GoLspAdapter {
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let (path, env) = delegate.which_command(OsString::from("gopls")).await?;
|
let env = delegate.shell_env().await;
|
||||||
|
let path = delegate.which("gopls".as_ref()).await?;
|
||||||
Some(LanguageServerBinary {
|
Some(LanguageServerBinary {
|
||||||
path,
|
path,
|
||||||
arguments: server_binary_arguments(),
|
arguments: server_binary_arguments(),
|
||||||
|
|
|
@ -39,7 +39,6 @@ mod tailwind;
|
||||||
mod terraform;
|
mod terraform;
|
||||||
mod toml;
|
mod toml;
|
||||||
mod typescript;
|
mod typescript;
|
||||||
mod uiua;
|
|
||||||
mod vue;
|
mod vue;
|
||||||
mod yaml;
|
mod yaml;
|
||||||
mod zig;
|
mod zig;
|
||||||
|
@ -114,7 +113,6 @@ pub fn init(
|
||||||
("toml", tree_sitter_toml::language()),
|
("toml", tree_sitter_toml::language()),
|
||||||
("tsx", tree_sitter_typescript::language_tsx()),
|
("tsx", tree_sitter_typescript::language_tsx()),
|
||||||
("typescript", tree_sitter_typescript::language_typescript()),
|
("typescript", tree_sitter_typescript::language_typescript()),
|
||||||
("uiua", tree_sitter_uiua::language()),
|
|
||||||
("vue", tree_sitter_vue::language()),
|
("vue", tree_sitter_vue::language()),
|
||||||
("yaml", tree_sitter_yaml::language()),
|
("yaml", tree_sitter_yaml::language()),
|
||||||
("zig", tree_sitter_zig::language()),
|
("zig", tree_sitter_zig::language()),
|
||||||
|
@ -344,7 +342,6 @@ pub fn init(
|
||||||
"vue",
|
"vue",
|
||||||
vec![Arc::new(vue::VueLspAdapter::new(node_runtime.clone()))]
|
vec![Arc::new(vue::VueLspAdapter::new(node_runtime.clone()))]
|
||||||
);
|
);
|
||||||
language!("uiua", vec![Arc::new(uiua::UiuaLanguageServer {})]);
|
|
||||||
language!("proto");
|
language!("proto");
|
||||||
language!("terraform", vec![Arc::new(terraform::TerraformLspAdapter)]);
|
language!("terraform", vec![Arc::new(terraform::TerraformLspAdapter)]);
|
||||||
language!(
|
language!(
|
||||||
|
|
|
@ -7,7 +7,6 @@ use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
use lsp::LanguageServerBinary;
|
use lsp::LanguageServerBinary;
|
||||||
use smol::fs;
|
use smol::fs;
|
||||||
use std::env::consts::{ARCH, OS};
|
use std::env::consts::{ARCH, OS};
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::{any::Any, path::PathBuf};
|
use std::{any::Any, path::PathBuf};
|
||||||
use util::async_maybe;
|
use util::async_maybe;
|
||||||
use util::github::latest_github_release;
|
use util::github::latest_github_release;
|
||||||
|
@ -45,7 +44,8 @@ impl LspAdapter for ZlsAdapter {
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let (path, env) = delegate.which_command(OsString::from("zls")).await?;
|
let env = delegate.shell_env().await;
|
||||||
|
let path = delegate.which("zls".as_ref()).await?;
|
||||||
Some(LanguageServerBinary {
|
Some(LanguageServerBinary {
|
||||||
path,
|
path,
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
|
|
|
@ -72,7 +72,7 @@ use std::{
|
||||||
cmp::{self, Ordering},
|
cmp::{self, Ordering},
|
||||||
convert::TryInto,
|
convert::TryInto,
|
||||||
env,
|
env,
|
||||||
ffi::OsString,
|
ffi::OsStr,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
mem,
|
mem,
|
||||||
num::NonZeroU32,
|
num::NonZeroU32,
|
||||||
|
@ -9390,6 +9390,7 @@ struct ProjectLspAdapterDelegate {
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
http_client: Arc<dyn HttpClient>,
|
http_client: Arc<dyn HttpClient>,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Arc<LanguageRegistry>,
|
||||||
|
shell_env: Mutex<Option<HashMap<String, String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectLspAdapterDelegate {
|
impl ProjectLspAdapterDelegate {
|
||||||
|
@ -9400,8 +9401,21 @@ impl ProjectLspAdapterDelegate {
|
||||||
fs: project.fs.clone(),
|
fs: project.fs.clone(),
|
||||||
http_client: project.client.http_client(),
|
http_client: project.client.http_client(),
|
||||||
language_registry: project.languages.clone(),
|
language_registry: project.languages.clone(),
|
||||||
|
shell_env: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn load_shell_env(&self) {
|
||||||
|
let worktree_abs_path = self.worktree.abs_path();
|
||||||
|
let shell_env = load_shell_environment(&worktree_abs_path)
|
||||||
|
.await
|
||||||
|
.with_context(|| {
|
||||||
|
format!("failed to determine load login shell environment in {worktree_abs_path:?}")
|
||||||
|
})
|
||||||
|
.log_err()
|
||||||
|
.unwrap_or_default();
|
||||||
|
*self.shell_env.lock() = Some(shell_env);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -9416,32 +9430,20 @@ impl LspAdapterDelegate for ProjectLspAdapterDelegate {
|
||||||
self.http_client.clone()
|
self.http_client.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn which_command(&self, command: OsString) -> Option<(PathBuf, HashMap<String, String>)> {
|
async fn shell_env(&self) -> HashMap<String, String> {
|
||||||
|
self.load_shell_env().await;
|
||||||
|
self.shell_env.lock().as_ref().cloned().unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn which(&self, command: &OsStr) -> Option<PathBuf> {
|
||||||
let worktree_abs_path = self.worktree.abs_path();
|
let worktree_abs_path = self.worktree.abs_path();
|
||||||
|
self.load_shell_env().await;
|
||||||
let shell_env = load_shell_environment(&worktree_abs_path)
|
let shell_path = self
|
||||||
.await
|
.shell_env
|
||||||
.with_context(|| {
|
.lock()
|
||||||
format!("failed to determine load login shell environment in {worktree_abs_path:?}")
|
.as_ref()
|
||||||
})
|
.and_then(|shell_env| shell_env.get("PATH").cloned());
|
||||||
.log_err();
|
which::which_in(command, shell_path.as_ref(), &worktree_abs_path).ok()
|
||||||
|
|
||||||
if let Some(shell_env) = shell_env {
|
|
||||||
let shell_path = shell_env.get("PATH");
|
|
||||||
match which::which_in(&command, shell_path, &worktree_abs_path) {
|
|
||||||
Ok(command_path) => Some((command_path, shell_env)),
|
|
||||||
Err(error) => {
|
|
||||||
log::warn!(
|
|
||||||
"failed to determine path for command {:?} in shell PATH {:?}: {error}",
|
|
||||||
command.to_string_lossy(),
|
|
||||||
shell_path.map(String::as_str).unwrap_or("")
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_status(
|
fn update_status(
|
||||||
|
|
16
extensions/uiua/Cargo.toml
Normal file
16
extensions/uiua/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "zed_uiua"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
license = "Apache-2.0"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
zed_extension_api = { path = "../../crates/extension_api" }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/uiua.rs"
|
||||||
|
crate-type = ["cdylib"]
|
13
extensions/uiua/extension.toml
Normal file
13
extensions/uiua/extension.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
id = "uiua"
|
||||||
|
name = "Uiua"
|
||||||
|
description = "Uiua support for Zed"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["Max Brunsfeld <max@zed.dev>"]
|
||||||
|
|
||||||
|
[language_servers.uiua]
|
||||||
|
name = "Uiua LSP"
|
||||||
|
language = "Uiua"
|
||||||
|
|
||||||
|
[grammars.uiua]
|
||||||
|
repository = "https://github.com/shnarazk/tree-sitter-uiua"
|
||||||
|
commit = "21dc2db39494585bf29a3f86d5add6e9d11a22ba"
|
27
extensions/uiua/src/uiua.rs
Normal file
27
extensions/uiua/src/uiua.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
use zed_extension_api::{self as zed, Result};
|
||||||
|
|
||||||
|
struct UiuaExtension;
|
||||||
|
|
||||||
|
impl zed::Extension for UiuaExtension {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn language_server_command(
|
||||||
|
&mut self,
|
||||||
|
_config: zed::LanguageServerConfig,
|
||||||
|
worktree: &zed::Worktree,
|
||||||
|
) -> Result<zed::Command> {
|
||||||
|
let path = worktree
|
||||||
|
.which("uiua")
|
||||||
|
.ok_or_else(|| "uiua is not installed".to_string())?;
|
||||||
|
|
||||||
|
Ok(zed::Command {
|
||||||
|
command: path,
|
||||||
|
args: vec!["lsp".to_string()],
|
||||||
|
env: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zed::register_extension!(UiuaExtension);
|
|
@ -1,15 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
WASI_ADAPTER_URL="https://github.com/bytecodealliance/wasmtime/releases/download/v18.0.2/wasi_snapshot_preview1.reactor.wasm"
|
|
||||||
WASI_SDK_URL="https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-21/wasi-sdk-21.0-macos.tar.gz"
|
|
||||||
|
|
||||||
echo "Downloading WASI adapter: $WASI_ADAPTER_URL"
|
|
||||||
curl -L $WASI_ADAPTER_URL -o target/wasi_snapshot_preview1.reactor.wasm
|
|
||||||
|
|
||||||
echo "Downloading WASI SDK: $WASI_SDK_URL"
|
|
||||||
mkdir -p target/wasi-sdk.archive
|
|
||||||
curl -L $WASI_SDK_URL | tar -xz - -C target/wasi-sdk.archive
|
|
||||||
rm -rf target/wasi-sdk/
|
|
||||||
mv -f target/wasi-sdk.archive/wasi-sdk-21.0/ target/wasi-sdk
|
|
Loading…
Add table
Add a link
Reference in a new issue