Detailed changes
@@ -89,9 +89,6 @@ jobs:
- name: cargo clippy
run: cargo xtask clippy
- - name: Install WASI dependencies
- run: script/setup-wasm
-
- name: Run tests
uses: ./.github/actions/run_tests
@@ -3011,15 +3011,6 @@ dependencies = [
"util",
]
-[[package]]
-name = "debugid"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
-dependencies = [
- "uuid",
-]
-
[[package]]
name = "deflate"
version = "0.8.6"
@@ -3159,16 +3150,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"
@@ -3556,6 +3537,7 @@ dependencies = [
"theme",
"toml 0.8.10",
"util",
+ "wasm-encoder",
"wasmparser",
"wasmtime",
"wasmtime-wasi",
@@ -4165,28 +4147,6 @@ dependencies = [
"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]]
name = "generic-array"
version = "0.14.7"
@@ -5060,26 +5020,6 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "jni"
version = "0.19.0"
@@ -5385,7 +5325,6 @@ dependencies = [
"tree-sitter-svelte",
"tree-sitter-toml",
"tree-sitter-typescript",
- "tree-sitter-uiua",
"tree-sitter-vue",
"tree-sitter-yaml",
"tree-sitter-zig",
@@ -10816,15 +10755,6 @@ dependencies = [
"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]]
name = "tree-sitter-vue"
version = "0.0.1"
@@ -11440,15 +11370,6 @@ dependencies = [
"leb128",
]
-[[package]]
-name = "wasm-encoder"
-version = "0.201.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a"
-dependencies = [
- "leb128",
-]
-
[[package]]
name = "wasm-metadata"
version = "0.10.20"
@@ -11461,7 +11382,7 @@ dependencies = [
"serde_derive",
"serde_json",
"spdx",
- "wasm-encoder 0.41.2",
+ "wasm-encoder",
"wasmparser",
]
@@ -11492,41 +11413,33 @@ version = "18.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c843b8bc4dd4f3a76173ba93405c71111d570af0d90ea5f6299c705d0c2add2"
dependencies = [
- "addr2line",
"anyhow",
"async-trait",
"bincode",
"bumpalo",
"cfg-if 1.0.0",
"encoding_rs",
- "fxprof-processed-profile",
"gimli",
"indexmap 2.0.0",
- "ittapi",
"libc",
"log",
"object",
"once_cell",
"paste",
- "rayon",
"rustix 0.38.30",
"serde",
"serde_derive",
"serde_json",
"target-lexicon",
- "wasm-encoder 0.41.2",
"wasmparser",
- "wasmtime-cache",
"wasmtime-component-macro",
"wasmtime-component-util",
"wasmtime-cranelift",
"wasmtime-environ",
"wasmtime-fiber",
- "wasmtime-jit-debug",
"wasmtime-jit-icache-coherence",
"wasmtime-runtime",
"wasmtime-winch",
- "wat",
"windows-sys 0.52.0",
]
@@ -11563,26 +11476,6 @@ dependencies = [
"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]]
name = "wasmtime-component-macro"
version = "18.0.2"
@@ -11664,7 +11557,7 @@ dependencies = [
"serde_derive",
"target-lexicon",
"thiserror",
- "wasm-encoder 0.41.2",
+ "wasm-encoder",
"wasmparser",
"wasmprinter",
"wasmtime-component-util",
@@ -11686,18 +11579,6 @@ dependencies = [
"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]]
name = "wasmtime-jit-icache-coherence"
version = "18.0.2"
@@ -11729,11 +11610,10 @@ dependencies = [
"psm",
"rustix 0.38.30",
"sptr",
- "wasm-encoder 0.41.2",
+ "wasm-encoder",
"wasmtime-asm-macros",
"wasmtime-environ",
"wasmtime-fiber",
- "wasmtime-jit-debug",
"wasmtime-versioned-export-macros",
"wasmtime-wmemcheck",
"windows-sys 0.52.0",
@@ -11840,28 +11720,6 @@ dependencies = [
"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]]
name = "wayland-backend"
version = "0.3.3"
@@ -12515,7 +12373,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
- "wasm-encoder 0.41.2",
+ "wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser 0.13.2",
@@ -12534,7 +12392,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
- "wasm-encoder 0.41.2",
+ "wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser 0.14.0",
@@ -12584,7 +12442,7 @@ dependencies = [
"anyhow",
"log",
"thiserror",
- "wast 35.0.2",
+ "wast",
]
[[package]]
@@ -13003,6 +12861,13 @@ dependencies = [
"zed_extension_api",
]
+[[package]]
+name = "zed_uiua"
+version = "0.0.1"
+dependencies = [
+ "zed_extension_api",
+]
+
[[package]]
name = "zeno"
version = "0.2.3"
@@ -92,7 +92,10 @@ members = [
"crates/workspace",
"crates/zed",
"crates/zed_actions",
+
"extensions/gleam",
+ "extensions/uiua",
+
"tooling/xtask",
]
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-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-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-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" }
@@ -317,7 +319,8 @@ unicase = "2.6"
url = "2.2"
uuid = { version = "1.1.2", features = ["v4"] }
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"
which = "6.0.0"
wit-component = "0.20"
@@ -37,7 +37,8 @@ settings.workspace = true
theme.workspace = true
toml.workspace = true
util.workspace = true
-wasmtime = { workspace = true, features = ["async"] }
+wasm-encoder.workspace = true
+wasmtime.workspace = true
wasmtime-wasi.workspace = true
wasmparser.workspace = true
wit-component.workspace = true
@@ -6,13 +6,16 @@ use async_tar::Archive;
use futures::io::BufReader;
use futures::AsyncReadExt;
use serde::Deserialize;
+use std::mem;
use std::{
env, fs,
path::{Path, PathBuf},
process::{Command, Stdio},
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;
/// Currently, we compile with Rust's `wasm32-wasi` target, which works with WASI `preview1`.
@@ -59,8 +62,11 @@ struct CargoTomlPackage {
}
impl ExtensionBuilder {
- pub fn new(cache_dir: PathBuf, http: Arc<dyn HttpClient>) -> Self {
- Self { cache_dir, http }
+ pub fn new(cache_dir: PathBuf) -> Self {
+ Self {
+ cache_dir,
+ http: http::client(),
+ }
}
pub async fn compile_extension(
@@ -138,6 +144,10 @@ impl ExtensionBuilder {
.encode()
.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)
.context("failed to write extension.wasm")?;
@@ -310,7 +320,7 @@ impl ExtensionBuilder {
async fn install_wasi_preview1_adapter_if_needed(&self) -> Result<Vec<u8>> {
let cache_path = self.cache_dir.join("wasi_snapshot_preview1.reactor.wasm");
if let Ok(content) = fs::read(&cache_path) {
- if wasmparser::Parser::is_core_wasm(&content) {
+ if Parser::is_core_wasm(&content) {
return Ok(content);
}
}
@@ -333,7 +343,7 @@ impl ExtensionBuilder {
fs::write(&cache_path, &content)
.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");
}
Ok(content)
@@ -379,4 +389,68 @@ impl ExtensionBuilder {
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(),
installed_dir,
index_path,
- builder: Arc::new(ExtensionBuilder::new(build_dir, http_client.clone())),
+ builder: Arc::new(ExtensionBuilder::new(build_dir)),
outstanding_operations: Default::default(),
modified_extensions: Default::default(),
reload_complete_senders: Vec::new(),
@@ -545,7 +545,7 @@ impl ExtensionStore {
builder
.compile_extension(
&extension_source_path,
- CompileExtensionOptions { release: true },
+ CompileExtensionOptions { release: false },
)
.await
}
@@ -7,10 +7,7 @@ use collections::BTreeMap;
use fs::{FakeFs, Fs, RealFs};
use futures::{io::BufReader, AsyncReadExt, StreamExt};
use gpui::{Context, TestAppContext};
-use language::{
- Language, LanguageConfig, LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus,
- LanguageServerName,
-};
+use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName};
use node_runtime::FakeNodeRuntime;
use parking_lot::Mutex;
use project::Project;
@@ -573,19 +570,6 @@ async fn test_extension_store_with_gleam_extension(cx: &mut TestAppContext) {
})
.await
.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 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_tar::Archive;
use async_trait::async_trait;
-use fs::Fs;
+use fs::{normalize_path, Fs};
use futures::{
channel::{
mpsc::{self, UnboundedSender},
@@ -72,8 +72,6 @@ type ExtensionCall = Box<
static WASM_ENGINE: OnceLock<wasmtime::Engine> = OnceLock::new();
-const EXTENSION_WORK_DIR_PATH: &str = "/zed/work";
-
impl WasmHost {
pub fn new(
fs: Arc<dyn Fs>,
@@ -181,11 +179,12 @@ impl WasmHost {
.await
.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")?;
let current_dir_preopen = work_dir_preopen
.try_clone()
.context("failed to preopen extension current directory")?;
+ let extension_work_dir = extension_work_dir.to_string_lossy();
let perms = wasi::FilePerms::all();
let dir_perms = wasi::DirPerms::all();
@@ -193,26 +192,24 @@ impl WasmHost {
Ok(wasi::WasiCtxBuilder::new()
.inherit_stdio()
.preopened_dir(current_dir_preopen, dir_perms, perms, ".")
- .preopened_dir(work_dir_preopen, dir_perms, perms, EXTENSION_WORK_DIR_PATH)
- .env("PWD", EXTENSION_WORK_DIR_PATH)
- .env("RUST_BACKTRACE", "1")
+ .preopened_dir(work_dir_preopen, dir_perms, perms, &extension_work_dir)
+ .env("PWD", &extension_work_dir)
+ .env("RUST_BACKTRACE", "full")
.build())
}
pub fn path_from_extension(&self, id: &Arc<str>, path: &Path) -> PathBuf {
- self.writeable_path_from_extension(id, path)
- .unwrap_or_else(|| path.to_path_buf())
+ let extension_work_dir = self.work_dir.join(id.as_ref());
+ normalize_path(&extension_work_dir.join(path))
}
- pub fn writeable_path_from_extension(&self, id: &Arc<str>, path: &Path) -> Option<PathBuf> {
- let path = path.strip_prefix(EXTENSION_WORK_DIR_PATH).unwrap_or(path);
- if path.is_relative() {
- let mut result = self.work_dir.clone();
- result.push(id.as_ref());
- result.extend(path);
- Some(result)
+ pub fn writeable_path_from_extension(&self, id: &Arc<str>, path: &Path) -> Result<PathBuf> {
+ let extension_work_dir = self.work_dir.join(id.as_ref());
+ let path = normalize_path(&extension_work_dir.join(path));
+ if path.starts_with(&extension_work_dir) {
+ Ok(path)
} 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]
impl wit::HostWorktree for WasmState {
async fn read_text_file(
@@ -273,6 +263,26 @@ impl wit::HostWorktree for WasmState {
.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<()> {
// we only ever hand out borrows of worktrees
Ok(())
@@ -395,8 +405,8 @@ impl wit::ExtensionImports for WasmState {
this.host.fs.create_dir(&extension_work_dir).await?;
let destination_path = this
- .writeable_path_from_extension(&path)
- .ok_or_else(|| anyhow!("cannot write to path {:?}", path))?;
+ .host
+ .writeable_path_from_extension(&this.manifest.id, &path)?;
let mut response = this
.host
@@ -61,14 +61,18 @@ world extension {
/// 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);
+ type env-vars = list<tuple<string, string>>;
+
record command {
command: string,
args: list<string>,
- env: list<tuple<string, string>>,
+ env: env-vars,
}
resource worktree {
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 {
@@ -40,7 +40,7 @@ use smol::future::FutureExt as _;
use std::{
any::Any,
cell::RefCell,
- ffi::OsString,
+ ffi::OsStr,
fmt::Debug,
hash::Hash,
mem,
@@ -277,7 +277,8 @@ pub trait LspAdapterDelegate: Send + Sync {
fn http_client(&self) -> Arc<dyn HttpClient>;
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>;
}
@@ -76,7 +76,6 @@ tree-sitter-scheme.workspace = true
tree-sitter-svelte.workspace = true
tree-sitter-toml.workspace = true
tree-sitter-typescript.workspace = true
-tree-sitter-uiua.workspace = true
tree-sitter-vue.workspace = true
tree-sitter-yaml.workspace = true
tree-sitter-zig.workspace = true
@@ -58,7 +58,8 @@ impl super::LspAdapter for GoLspAdapter {
&self,
delegate: &dyn LspAdapterDelegate,
) -> 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 {
path,
arguments: server_binary_arguments(),
@@ -39,7 +39,6 @@ mod tailwind;
mod terraform;
mod toml;
mod typescript;
-mod uiua;
mod vue;
mod yaml;
mod zig;
@@ -114,7 +113,6 @@ pub fn init(
("toml", tree_sitter_toml::language()),
("tsx", tree_sitter_typescript::language_tsx()),
("typescript", tree_sitter_typescript::language_typescript()),
- ("uiua", tree_sitter_uiua::language()),
("vue", tree_sitter_vue::language()),
("yaml", tree_sitter_yaml::language()),
("zig", tree_sitter_zig::language()),
@@ -344,7 +342,6 @@ pub fn init(
"vue",
vec![Arc::new(vue::VueLspAdapter::new(node_runtime.clone()))]
);
- language!("uiua", vec![Arc::new(uiua::UiuaLanguageServer {})]);
language!("proto");
language!("terraform", vec![Arc::new(terraform::TerraformLspAdapter)]);
language!(
@@ -7,7 +7,6 @@ use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary;
use smol::fs;
use std::env::consts::{ARCH, OS};
-use std::ffi::OsString;
use std::{any::Any, path::PathBuf};
use util::async_maybe;
use util::github::latest_github_release;
@@ -45,7 +44,8 @@ impl LspAdapter for ZlsAdapter {
&self,
delegate: &dyn LspAdapterDelegate,
) -> 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 {
path,
arguments: vec![],
@@ -72,7 +72,7 @@ use std::{
cmp::{self, Ordering},
convert::TryInto,
env,
- ffi::OsString,
+ ffi::OsStr,
hash::Hash,
mem,
num::NonZeroU32,
@@ -9390,6 +9390,7 @@ struct ProjectLspAdapterDelegate {
fs: Arc<dyn Fs>,
http_client: Arc<dyn HttpClient>,
language_registry: Arc<LanguageRegistry>,
+ shell_env: Mutex<Option<HashMap<String, String>>>,
}
impl ProjectLspAdapterDelegate {
@@ -9400,8 +9401,21 @@ impl ProjectLspAdapterDelegate {
fs: project.fs.clone(),
http_client: project.client.http_client(),
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]
@@ -9416,32 +9430,20 @@ impl LspAdapterDelegate for ProjectLspAdapterDelegate {
self.http_client.clone()
}
- async fn which_command(&self, command: OsString) -> Option<(PathBuf, HashMap<String, String>)> {
- let worktree_abs_path = self.worktree.abs_path();
+ async fn shell_env(&self) -> HashMap<String, String> {
+ self.load_shell_env().await;
+ self.shell_env.lock().as_ref().cloned().unwrap_or_default()
+ }
- 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();
-
- 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
- }
+ async fn which(&self, command: &OsStr) -> Option<PathBuf> {
+ let worktree_abs_path = self.worktree.abs_path();
+ self.load_shell_env().await;
+ let shell_path = self
+ .shell_env
+ .lock()
+ .as_ref()
+ .and_then(|shell_env| shell_env.get("PATH").cloned());
+ which::which_in(command, shell_path.as_ref(), &worktree_abs_path).ok()
}
fn update_status(
@@ -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"]
@@ -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"
@@ -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