zed_extension_api: Fork new version (#12160)
This PR forks a new version of the `zed_extension_api` in preparation for some upcoming changes that require breaking changes to the WIT. Release Notes: - N/A --------- Co-authored-by: Max <max@zed.dev>
This commit is contained in:
parent
2564d5d648
commit
80bd40cfa3
13 changed files with 886 additions and 321 deletions
38
Cargo.lock
generated
38
Cargo.lock
generated
|
@ -13160,28 +13160,28 @@ dependencies = [
|
||||||
name = "zed_dart"
|
name = "zed_dart"
|
||||||
version = "0.0.2"
|
version = "0.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_deno"
|
name = "zed_deno"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_elixir"
|
name = "zed_elixir"
|
||||||
version = "0.0.4"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_elm"
|
name = "zed_elm"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -13210,6 +13210,8 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_extension_api"
|
name = "zed_extension_api"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77ca8bcaea3feb2d2ce9dbeb061ee48365312a351faa7014c417b0365fe9e459"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -13218,9 +13220,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_extension_api"
|
name = "zed_extension_api"
|
||||||
version = "0.0.6"
|
version = "0.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77ca8bcaea3feb2d2ce9dbeb061ee48365312a351faa7014c417b0365fe9e459"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -13231,42 +13231,42 @@ dependencies = [
|
||||||
name = "zed_gleam"
|
name = "zed_gleam"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_glsl"
|
name = "zed_glsl"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_haskell"
|
name = "zed_haskell"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_html"
|
name = "zed_html"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_lua"
|
name = "zed_lua"
|
||||||
version = "0.0.2"
|
version = "0.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_ocaml"
|
name = "zed_ocaml"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -13294,28 +13294,28 @@ dependencies = [
|
||||||
name = "zed_ruby"
|
name = "zed_ruby"
|
||||||
version = "0.0.4"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_svelte"
|
name = "zed_svelte"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_terraform"
|
name = "zed_terraform"
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_toml"
|
name = "zed_toml"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -13329,14 +13329,14 @@ dependencies = [
|
||||||
name = "zed_vue"
|
name = "zed_vue"
|
||||||
version = "0.0.2"
|
version = "0.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_zig"
|
name = "zed_zig"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
mod since_v0_0_1;
|
mod since_v0_0_1;
|
||||||
mod since_v0_0_4;
|
mod since_v0_0_4;
|
||||||
mod since_v0_0_6;
|
mod since_v0_0_6;
|
||||||
use since_v0_0_6 as latest;
|
mod since_v0_0_7;
|
||||||
|
use since_v0_0_7 as latest;
|
||||||
|
|
||||||
use super::{wasm_engine, WasmState};
|
use super::{wasm_engine, WasmState};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
@ -46,6 +47,7 @@ pub fn wasm_api_version_range() -> RangeInclusive<SemanticVersion> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Extension {
|
pub enum Extension {
|
||||||
|
V007(since_v0_0_7::Extension),
|
||||||
V006(since_v0_0_6::Extension),
|
V006(since_v0_0_6::Extension),
|
||||||
V004(since_v0_0_4::Extension),
|
V004(since_v0_0_4::Extension),
|
||||||
V001(since_v0_0_1::Extension),
|
V001(since_v0_0_1::Extension),
|
||||||
|
@ -62,6 +64,15 @@ impl Extension {
|
||||||
latest::Extension::instantiate_async(store, &component, latest::linker())
|
latest::Extension::instantiate_async(store, &component, latest::linker())
|
||||||
.await
|
.await
|
||||||
.context("failed to instantiate wasm extension")?;
|
.context("failed to instantiate wasm extension")?;
|
||||||
|
Ok((Self::V007(extension), instance))
|
||||||
|
} else if version >= since_v0_0_6::MIN_VERSION {
|
||||||
|
let (extension, instance) = since_v0_0_6::Extension::instantiate_async(
|
||||||
|
store,
|
||||||
|
&component,
|
||||||
|
since_v0_0_6::linker(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.context("failed to instantiate wasm extension")?;
|
||||||
Ok((Self::V006(extension), instance))
|
Ok((Self::V006(extension), instance))
|
||||||
} else if version >= since_v0_0_4::MIN_VERSION {
|
} else if version >= since_v0_0_4::MIN_VERSION {
|
||||||
let (extension, instance) = since_v0_0_4::Extension::instantiate_async(
|
let (extension, instance) = since_v0_0_4::Extension::instantiate_async(
|
||||||
|
@ -86,6 +97,7 @@ impl Extension {
|
||||||
|
|
||||||
pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
|
pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
|
Extension::V007(ext) => ext.call_init_extension(store).await,
|
||||||
Extension::V006(ext) => ext.call_init_extension(store).await,
|
Extension::V006(ext) => ext.call_init_extension(store).await,
|
||||||
Extension::V004(ext) => ext.call_init_extension(store).await,
|
Extension::V004(ext) => ext.call_init_extension(store).await,
|
||||||
Extension::V001(ext) => ext.call_init_extension(store).await,
|
Extension::V001(ext) => ext.call_init_extension(store).await,
|
||||||
|
@ -100,10 +112,14 @@ impl Extension {
|
||||||
resource: Resource<Arc<dyn LspAdapterDelegate>>,
|
resource: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
) -> Result<Result<Command, String>> {
|
) -> Result<Result<Command, String>> {
|
||||||
match self {
|
match self {
|
||||||
Extension::V006(ext) => {
|
Extension::V007(ext) => {
|
||||||
ext.call_language_server_command(store, &language_server_id.0, resource)
|
ext.call_language_server_command(store, &language_server_id.0, resource)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
Extension::V006(ext) => Ok(ext
|
||||||
|
.call_language_server_command(store, &language_server_id.0, resource)
|
||||||
|
.await?
|
||||||
|
.map(|command| command.into())),
|
||||||
Extension::V004(ext) => Ok(ext
|
Extension::V004(ext) => Ok(ext
|
||||||
.call_language_server_command(store, config, resource)
|
.call_language_server_command(store, config, resource)
|
||||||
.await?
|
.await?
|
||||||
|
@ -123,6 +139,14 @@ impl Extension {
|
||||||
resource: Resource<Arc<dyn LspAdapterDelegate>>,
|
resource: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
) -> Result<Result<Option<String>, String>> {
|
) -> Result<Result<Option<String>, String>> {
|
||||||
match self {
|
match self {
|
||||||
|
Extension::V007(ext) => {
|
||||||
|
ext.call_language_server_initialization_options(
|
||||||
|
store,
|
||||||
|
&language_server_id.0,
|
||||||
|
resource,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
Extension::V006(ext) => {
|
Extension::V006(ext) => {
|
||||||
ext.call_language_server_initialization_options(
|
ext.call_language_server_initialization_options(
|
||||||
store,
|
store,
|
||||||
|
@ -153,6 +177,14 @@ impl Extension {
|
||||||
resource: Resource<Arc<dyn LspAdapterDelegate>>,
|
resource: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
) -> Result<Result<Option<String>, String>> {
|
) -> Result<Result<Option<String>, String>> {
|
||||||
match self {
|
match self {
|
||||||
|
Extension::V007(ext) => {
|
||||||
|
ext.call_language_server_workspace_configuration(
|
||||||
|
store,
|
||||||
|
&language_server_id.0,
|
||||||
|
resource,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
Extension::V006(ext) => {
|
Extension::V006(ext) => {
|
||||||
ext.call_language_server_workspace_configuration(
|
ext.call_language_server_workspace_configuration(
|
||||||
store,
|
store,
|
||||||
|
@ -172,11 +204,20 @@ impl Extension {
|
||||||
completions: Vec<latest::Completion>,
|
completions: Vec<latest::Completion>,
|
||||||
) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
|
) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
|
||||||
match self {
|
match self {
|
||||||
Extension::V001(_) | Extension::V004(_) => Ok(Ok(Vec::new())),
|
Extension::V007(ext) => {
|
||||||
Extension::V006(ext) => {
|
|
||||||
ext.call_labels_for_completions(store, &language_server_id.0, &completions)
|
ext.call_labels_for_completions(store, &language_server_id.0, &completions)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
Extension::V006(ext) => Ok(ext
|
||||||
|
.call_labels_for_completions(store, &language_server_id.0, &completions)
|
||||||
|
.await?
|
||||||
|
.map(|labels| {
|
||||||
|
labels
|
||||||
|
.into_iter()
|
||||||
|
.map(|label| label.map(Into::into))
|
||||||
|
.collect()
|
||||||
|
})),
|
||||||
|
Extension::V001(_) | Extension::V004(_) => Ok(Ok(Vec::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,11 +228,20 @@ impl Extension {
|
||||||
symbols: Vec<latest::Symbol>,
|
symbols: Vec<latest::Symbol>,
|
||||||
) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
|
) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
|
||||||
match self {
|
match self {
|
||||||
Extension::V001(_) | Extension::V004(_) => Ok(Ok(Vec::new())),
|
Extension::V007(ext) => {
|
||||||
Extension::V006(ext) => {
|
|
||||||
ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
|
ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
Extension::V006(ext) => Ok(ext
|
||||||
|
.call_labels_for_symbols(store, &language_server_id.0, &symbols)
|
||||||
|
.await?
|
||||||
|
.map(|labels| {
|
||||||
|
labels
|
||||||
|
.into_iter()
|
||||||
|
.map(|label| label.map(Into::into))
|
||||||
|
.collect()
|
||||||
|
})),
|
||||||
|
Extension::V001(_) | Extension::V004(_) => Ok(Ok(Vec::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,26 @@
|
||||||
use crate::wasm_host::{wit::ToWasmtimeResult, WasmState};
|
use super::latest;
|
||||||
use ::settings::Settings;
|
use crate::wasm_host::WasmState;
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::Result;
|
||||||
use async_compression::futures::bufread::GzipDecoder;
|
|
||||||
use async_tar::Archive;
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::{io::BufReader, FutureExt as _};
|
use language::LspAdapterDelegate;
|
||||||
use language::{
|
|
||||||
language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate,
|
|
||||||
};
|
|
||||||
use project::project_settings::ProjectSettings;
|
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
use std::{
|
use std::sync::{Arc, OnceLock};
|
||||||
env,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
sync::{Arc, OnceLock},
|
|
||||||
};
|
|
||||||
use util::maybe;
|
|
||||||
use wasmtime::component::{Linker, Resource};
|
use wasmtime::component::{Linker, Resource};
|
||||||
|
|
||||||
pub const MIN_VERSION: SemanticVersion = SemanticVersion::new(0, 0, 6);
|
pub const MIN_VERSION: SemanticVersion = SemanticVersion::new(0, 0, 6);
|
||||||
pub const MAX_VERSION: SemanticVersion = SemanticVersion::new(0, 0, 6);
|
|
||||||
|
|
||||||
wasmtime::component::bindgen!({
|
wasmtime::component::bindgen!({
|
||||||
async: true,
|
async: true,
|
||||||
path: "../extension_api/wit/since_v0.0.6",
|
path: "../extension_api/wit/since_v0.0.6",
|
||||||
with: {
|
with: {
|
||||||
"worktree": ExtensionWorktree,
|
"worktree": ExtensionWorktree,
|
||||||
|
"zed:extension/github": latest::zed::extension::github,
|
||||||
|
"zed:extension/lsp": latest::zed::extension::lsp,
|
||||||
|
"zed:extension/nodejs": latest::zed::extension::nodejs,
|
||||||
|
"zed:extension/platform": latest::zed::extension::platform,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
pub use self::zed::extension::*;
|
|
||||||
|
|
||||||
mod settings {
|
mod settings {
|
||||||
include!("../../../../extension_api/wit/since_v0.0.6/settings.rs");
|
include!("../../../../extension_api/wit/since_v0.0.6/settings.rs");
|
||||||
}
|
}
|
||||||
|
@ -39,7 +29,93 @@ pub type ExtensionWorktree = Arc<dyn LspAdapterDelegate>;
|
||||||
|
|
||||||
pub fn linker() -> &'static Linker<WasmState> {
|
pub fn linker() -> &'static Linker<WasmState> {
|
||||||
static LINKER: OnceLock<Linker<WasmState>> = OnceLock::new();
|
static LINKER: OnceLock<Linker<WasmState>> = OnceLock::new();
|
||||||
LINKER.get_or_init(|| super::new_linker(Extension::add_to_linker))
|
LINKER.get_or_init(|| {
|
||||||
|
super::new_linker(|linker, f| {
|
||||||
|
Extension::add_to_linker(linker, f)?;
|
||||||
|
latest::zed::extension::github::add_to_linker(linker, f)?;
|
||||||
|
latest::zed::extension::nodejs::add_to_linker(linker, f)?;
|
||||||
|
latest::zed::extension::platform::add_to_linker(linker, f)?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Command> for latest::Command {
|
||||||
|
fn from(value: Command) -> Self {
|
||||||
|
Self {
|
||||||
|
command: value.command,
|
||||||
|
args: value.args,
|
||||||
|
env: value.env,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SettingsLocation> for latest::SettingsLocation {
|
||||||
|
fn from(value: SettingsLocation) -> Self {
|
||||||
|
Self {
|
||||||
|
worktree_id: value.worktree_id,
|
||||||
|
path: value.path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LanguageServerInstallationStatus> for latest::LanguageServerInstallationStatus {
|
||||||
|
fn from(value: LanguageServerInstallationStatus) -> Self {
|
||||||
|
match value {
|
||||||
|
LanguageServerInstallationStatus::None => Self::None,
|
||||||
|
LanguageServerInstallationStatus::Downloading => Self::Downloading,
|
||||||
|
LanguageServerInstallationStatus::CheckingForUpdate => Self::CheckingForUpdate,
|
||||||
|
LanguageServerInstallationStatus::Failed(message) => Self::Failed(message),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DownloadedFileType> for latest::DownloadedFileType {
|
||||||
|
fn from(value: DownloadedFileType) -> Self {
|
||||||
|
match value {
|
||||||
|
DownloadedFileType::Gzip => Self::Gzip,
|
||||||
|
DownloadedFileType::GzipTar => Self::GzipTar,
|
||||||
|
DownloadedFileType::Zip => Self::Zip,
|
||||||
|
DownloadedFileType::Uncompressed => Self::Uncompressed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Range> for latest::Range {
|
||||||
|
fn from(value: Range) -> Self {
|
||||||
|
Self {
|
||||||
|
start: value.start,
|
||||||
|
end: value.end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodeLabelSpan> for latest::CodeLabelSpan {
|
||||||
|
fn from(value: CodeLabelSpan) -> Self {
|
||||||
|
match value {
|
||||||
|
CodeLabelSpan::CodeRange(range) => Self::CodeRange(range.into()),
|
||||||
|
CodeLabelSpan::Literal(literal) => Self::Literal(literal.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodeLabelSpanLiteral> for latest::CodeLabelSpanLiteral {
|
||||||
|
fn from(value: CodeLabelSpanLiteral) -> Self {
|
||||||
|
Self {
|
||||||
|
text: value.text,
|
||||||
|
highlight_name: value.highlight_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodeLabel> for latest::CodeLabel {
|
||||||
|
fn from(value: CodeLabel) -> Self {
|
||||||
|
Self {
|
||||||
|
code: value.code,
|
||||||
|
spans: value.spans.into_iter().map(Into::into).collect(),
|
||||||
|
filter_range: value.filter_range.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -48,16 +124,14 @@ impl HostWorktree for WasmState {
|
||||||
&mut self,
|
&mut self,
|
||||||
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
) -> wasmtime::Result<u64> {
|
) -> wasmtime::Result<u64> {
|
||||||
let delegate = self.table.get(&delegate)?;
|
latest::HostWorktree::id(self, delegate).await
|
||||||
Ok(delegate.worktree_id())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn root_path(
|
async fn root_path(
|
||||||
&mut self,
|
&mut self,
|
||||||
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
) -> wasmtime::Result<String> {
|
) -> wasmtime::Result<String> {
|
||||||
let delegate = self.table.get(&delegate)?;
|
latest::HostWorktree::root_path(self, delegate).await
|
||||||
Ok(delegate.worktree_root_path().to_string_lossy().to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_text_file(
|
async fn read_text_file(
|
||||||
|
@ -65,19 +139,14 @@ impl HostWorktree for WasmState {
|
||||||
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
path: String,
|
path: String,
|
||||||
) -> wasmtime::Result<Result<String, String>> {
|
) -> wasmtime::Result<Result<String, String>> {
|
||||||
let delegate = self.table.get(&delegate)?;
|
latest::HostWorktree::read_text_file(self, delegate, path).await
|
||||||
Ok(delegate
|
|
||||||
.read_text_file(path.into())
|
|
||||||
.await
|
|
||||||
.map_err(|error| error.to_string()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn shell_env(
|
async fn shell_env(
|
||||||
&mut self,
|
&mut self,
|
||||||
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
) -> wasmtime::Result<EnvVars> {
|
) -> wasmtime::Result<EnvVars> {
|
||||||
let delegate = self.table.get(&delegate)?;
|
latest::HostWorktree::shell_env(self, delegate).await
|
||||||
Ok(delegate.shell_env().await.into_iter().collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn which(
|
async fn which(
|
||||||
|
@ -85,11 +154,7 @@ impl HostWorktree for WasmState {
|
||||||
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
binary_name: String,
|
binary_name: String,
|
||||||
) -> wasmtime::Result<Option<String>> {
|
) -> wasmtime::Result<Option<String>> {
|
||||||
let delegate = self.table.get(&delegate)?;
|
latest::HostWorktree::which(self, delegate, binary_name).await
|
||||||
Ok(delegate
|
|
||||||
.which(binary_name.as_ref())
|
|
||||||
.await
|
|
||||||
.map(|path| path.to_string_lossy().to_string()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drop(&mut self, _worktree: Resource<Worktree>) -> Result<()> {
|
fn drop(&mut self, _worktree: Resource<Worktree>) -> Result<()> {
|
||||||
|
@ -98,107 +163,6 @@ impl HostWorktree for WasmState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl nodejs::Host for WasmState {
|
|
||||||
async fn node_binary_path(&mut self) -> wasmtime::Result<Result<String, String>> {
|
|
||||||
self.host
|
|
||||||
.node_runtime
|
|
||||||
.binary_path()
|
|
||||||
.await
|
|
||||||
.map(|path| path.to_string_lossy().to_string())
|
|
||||||
.to_wasmtime_result()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn npm_package_latest_version(
|
|
||||||
&mut self,
|
|
||||||
package_name: String,
|
|
||||||
) -> wasmtime::Result<Result<String, String>> {
|
|
||||||
self.host
|
|
||||||
.node_runtime
|
|
||||||
.npm_package_latest_version(&package_name)
|
|
||||||
.await
|
|
||||||
.to_wasmtime_result()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn npm_package_installed_version(
|
|
||||||
&mut self,
|
|
||||||
package_name: String,
|
|
||||||
) -> wasmtime::Result<Result<Option<String>, String>> {
|
|
||||||
self.host
|
|
||||||
.node_runtime
|
|
||||||
.npm_package_installed_version(&self.work_dir(), &package_name)
|
|
||||||
.await
|
|
||||||
.to_wasmtime_result()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn npm_install_package(
|
|
||||||
&mut self,
|
|
||||||
package_name: String,
|
|
||||||
version: String,
|
|
||||||
) -> wasmtime::Result<Result<(), String>> {
|
|
||||||
self.host
|
|
||||||
.node_runtime
|
|
||||||
.npm_install_packages(&self.work_dir(), &[(&package_name, &version)])
|
|
||||||
.await
|
|
||||||
.to_wasmtime_result()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl lsp::Host for WasmState {}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl github::Host for WasmState {
|
|
||||||
async fn latest_github_release(
|
|
||||||
&mut self,
|
|
||||||
repo: String,
|
|
||||||
options: github::GithubReleaseOptions,
|
|
||||||
) -> wasmtime::Result<Result<github::GithubRelease, String>> {
|
|
||||||
maybe!(async {
|
|
||||||
let release = http::github::latest_github_release(
|
|
||||||
&repo,
|
|
||||||
options.require_assets,
|
|
||||||
options.pre_release,
|
|
||||||
self.host.http_client.clone(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(github::GithubRelease {
|
|
||||||
version: release.tag_name,
|
|
||||||
assets: release
|
|
||||||
.assets
|
|
||||||
.into_iter()
|
|
||||||
.map(|asset| github::GithubReleaseAsset {
|
|
||||||
name: asset.name,
|
|
||||||
download_url: asset.browser_download_url,
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.to_wasmtime_result()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl platform::Host for WasmState {
|
|
||||||
async fn current_platform(&mut self) -> Result<(platform::Os, platform::Architecture)> {
|
|
||||||
Ok((
|
|
||||||
match env::consts::OS {
|
|
||||||
"macos" => platform::Os::Mac,
|
|
||||||
"linux" => platform::Os::Linux,
|
|
||||||
"windows" => platform::Os::Windows,
|
|
||||||
_ => panic!("unsupported os"),
|
|
||||||
},
|
|
||||||
match env::consts::ARCH {
|
|
||||||
"aarch64" => platform::Architecture::Aarch64,
|
|
||||||
"x86" => platform::Architecture::X86,
|
|
||||||
"x86_64" => platform::Architecture::X8664,
|
|
||||||
_ => panic!("unsupported architecture"),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl ExtensionImports for WasmState {
|
impl ExtensionImports for WasmState {
|
||||||
async fn get_settings(
|
async fn get_settings(
|
||||||
|
@ -207,50 +171,13 @@ impl ExtensionImports for WasmState {
|
||||||
category: String,
|
category: String,
|
||||||
key: Option<String>,
|
key: Option<String>,
|
||||||
) -> wasmtime::Result<Result<String, String>> {
|
) -> wasmtime::Result<Result<String, String>> {
|
||||||
self.on_main_thread(|cx| {
|
latest::ExtensionImports::get_settings(
|
||||||
async move {
|
self,
|
||||||
let location = location
|
location.map(|location| location.into()),
|
||||||
.as_ref()
|
category,
|
||||||
.map(|location| ::settings::SettingsLocation {
|
key,
|
||||||
worktree_id: location.worktree_id as usize,
|
)
|
||||||
path: Path::new(&location.path),
|
.await
|
||||||
});
|
|
||||||
|
|
||||||
cx.update(|cx| match category.as_str() {
|
|
||||||
"language" => {
|
|
||||||
let settings =
|
|
||||||
AllLanguageSettings::get(location, cx).language(key.as_deref());
|
|
||||||
Ok(serde_json::to_string(&settings::LanguageSettings {
|
|
||||||
tab_size: settings.tab_size,
|
|
||||||
})?)
|
|
||||||
}
|
|
||||||
"lsp" => {
|
|
||||||
let settings = key
|
|
||||||
.and_then(|key| {
|
|
||||||
ProjectSettings::get(location, cx)
|
|
||||||
.lsp
|
|
||||||
.get(&Arc::<str>::from(key))
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_default();
|
|
||||||
Ok(serde_json::to_string(&settings::LspSettings {
|
|
||||||
binary: settings.binary.map(|binary| settings::BinarySettings {
|
|
||||||
path: binary.path,
|
|
||||||
arguments: binary.arguments,
|
|
||||||
}),
|
|
||||||
settings: settings.settings,
|
|
||||||
initialization_options: settings.initialization_options,
|
|
||||||
})?)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
bail!("Unknown settings category: {}", category);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
.boxed_local()
|
|
||||||
})
|
|
||||||
.await?
|
|
||||||
.to_wasmtime_result()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_language_server_installation_status(
|
async fn set_language_server_installation_status(
|
||||||
|
@ -258,23 +185,12 @@ impl ExtensionImports for WasmState {
|
||||||
server_name: String,
|
server_name: String,
|
||||||
status: LanguageServerInstallationStatus,
|
status: LanguageServerInstallationStatus,
|
||||||
) -> wasmtime::Result<()> {
|
) -> wasmtime::Result<()> {
|
||||||
let status = match status {
|
latest::ExtensionImports::set_language_server_installation_status(
|
||||||
LanguageServerInstallationStatus::CheckingForUpdate => {
|
self,
|
||||||
LanguageServerBinaryStatus::CheckingForUpdate
|
server_name,
|
||||||
}
|
status.into(),
|
||||||
LanguageServerInstallationStatus::Downloading => {
|
)
|
||||||
LanguageServerBinaryStatus::Downloading
|
.await
|
||||||
}
|
|
||||||
LanguageServerInstallationStatus::None => LanguageServerBinaryStatus::None,
|
|
||||||
LanguageServerInstallationStatus::Failed(error) => {
|
|
||||||
LanguageServerBinaryStatus::Failed { error }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.host
|
|
||||||
.language_registry
|
|
||||||
.update_lsp_status(language::LanguageServerName(server_name.into()), status);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn download_file(
|
async fn download_file(
|
||||||
|
@ -283,103 +199,10 @@ impl ExtensionImports for WasmState {
|
||||||
path: String,
|
path: String,
|
||||||
file_type: DownloadedFileType,
|
file_type: DownloadedFileType,
|
||||||
) -> wasmtime::Result<Result<(), String>> {
|
) -> wasmtime::Result<Result<(), String>> {
|
||||||
maybe!(async {
|
latest::ExtensionImports::download_file(self, url, path, file_type.into()).await
|
||||||
let path = PathBuf::from(path);
|
|
||||||
let extension_work_dir = self.host.work_dir.join(self.manifest.id.as_ref());
|
|
||||||
|
|
||||||
self.host.fs.create_dir(&extension_work_dir).await?;
|
|
||||||
|
|
||||||
let destination_path = self
|
|
||||||
.host
|
|
||||||
.writeable_path_from_extension(&self.manifest.id, &path)?;
|
|
||||||
|
|
||||||
let mut response = self
|
|
||||||
.host
|
|
||||||
.http_client
|
|
||||||
.get(&url, Default::default(), true)
|
|
||||||
.await
|
|
||||||
.map_err(|err| anyhow!("error downloading release: {}", err))?;
|
|
||||||
|
|
||||||
if !response.status().is_success() {
|
|
||||||
Err(anyhow!(
|
|
||||||
"download failed with status {}",
|
|
||||||
response.status().to_string()
|
|
||||||
))?;
|
|
||||||
}
|
|
||||||
let body = BufReader::new(response.body_mut());
|
|
||||||
|
|
||||||
match file_type {
|
|
||||||
DownloadedFileType::Uncompressed => {
|
|
||||||
futures::pin_mut!(body);
|
|
||||||
self.host
|
|
||||||
.fs
|
|
||||||
.create_file_with(&destination_path, body)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
DownloadedFileType::Gzip => {
|
|
||||||
let body = GzipDecoder::new(body);
|
|
||||||
futures::pin_mut!(body);
|
|
||||||
self.host
|
|
||||||
.fs
|
|
||||||
.create_file_with(&destination_path, body)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
DownloadedFileType::GzipTar => {
|
|
||||||
let body = GzipDecoder::new(body);
|
|
||||||
futures::pin_mut!(body);
|
|
||||||
self.host
|
|
||||||
.fs
|
|
||||||
.extract_tar_file(&destination_path, Archive::new(body))
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
DownloadedFileType::Zip => {
|
|
||||||
let file_name = destination_path
|
|
||||||
.file_name()
|
|
||||||
.ok_or_else(|| anyhow!("invalid download path"))?
|
|
||||||
.to_string_lossy();
|
|
||||||
let zip_filename = format!("{file_name}.zip");
|
|
||||||
let mut zip_path = destination_path.clone();
|
|
||||||
zip_path.set_file_name(zip_filename);
|
|
||||||
|
|
||||||
futures::pin_mut!(body);
|
|
||||||
self.host.fs.create_file_with(&zip_path, body).await?;
|
|
||||||
|
|
||||||
let unzip_status = std::process::Command::new("unzip")
|
|
||||||
.current_dir(&extension_work_dir)
|
|
||||||
.arg("-d")
|
|
||||||
.arg(&destination_path)
|
|
||||||
.arg(&zip_path)
|
|
||||||
.output()?
|
|
||||||
.status;
|
|
||||||
if !unzip_status.success() {
|
|
||||||
Err(anyhow!("failed to unzip {} archive", path.display()))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.to_wasmtime_result()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn make_file_executable(&mut self, path: String) -> wasmtime::Result<Result<(), String>> {
|
async fn make_file_executable(&mut self, path: String) -> wasmtime::Result<Result<(), String>> {
|
||||||
#[allow(unused)]
|
latest::ExtensionImports::make_file_executable(self, path).await
|
||||||
let path = self
|
|
||||||
.host
|
|
||||||
.writeable_path_from_extension(&self.manifest.id, Path::new(&path))?;
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
use std::fs::{self, Permissions};
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
|
|
||||||
return fs::set_permissions(&path, Permissions::from_mode(0o755))
|
|
||||||
.map_err(|error| anyhow!("failed to set permissions for path {path:?}: {error}"))
|
|
||||||
.to_wasmtime_result();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
|
||||||
Ok(Ok(()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
385
crates/extension/src/wasm_host/wit/since_v0_0_7.rs
Normal file
385
crates/extension/src/wasm_host/wit/since_v0_0_7.rs
Normal file
|
@ -0,0 +1,385 @@
|
||||||
|
use crate::wasm_host::{wit::ToWasmtimeResult, WasmState};
|
||||||
|
use ::settings::Settings;
|
||||||
|
use anyhow::{anyhow, bail, Result};
|
||||||
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
|
use async_tar::Archive;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use futures::{io::BufReader, FutureExt as _};
|
||||||
|
use language::{
|
||||||
|
language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate,
|
||||||
|
};
|
||||||
|
use project::project_settings::ProjectSettings;
|
||||||
|
use semantic_version::SemanticVersion;
|
||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
sync::{Arc, OnceLock},
|
||||||
|
};
|
||||||
|
use util::maybe;
|
||||||
|
use wasmtime::component::{Linker, Resource};
|
||||||
|
|
||||||
|
pub const MIN_VERSION: SemanticVersion = SemanticVersion::new(0, 0, 7);
|
||||||
|
pub const MAX_VERSION: SemanticVersion = SemanticVersion::new(0, 0, 7);
|
||||||
|
|
||||||
|
wasmtime::component::bindgen!({
|
||||||
|
async: true,
|
||||||
|
path: "../extension_api/wit/since_v0.0.7",
|
||||||
|
with: {
|
||||||
|
"worktree": ExtensionWorktree,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
pub use self::zed::extension::*;
|
||||||
|
|
||||||
|
mod settings {
|
||||||
|
include!("../../../../extension_api/wit/since_v0.0.7/settings.rs");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ExtensionWorktree = Arc<dyn LspAdapterDelegate>;
|
||||||
|
|
||||||
|
pub fn linker() -> &'static Linker<WasmState> {
|
||||||
|
static LINKER: OnceLock<Linker<WasmState>> = OnceLock::new();
|
||||||
|
LINKER.get_or_init(|| super::new_linker(Extension::add_to_linker))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl HostWorktree for WasmState {
|
||||||
|
async fn id(
|
||||||
|
&mut self,
|
||||||
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
|
) -> wasmtime::Result<u64> {
|
||||||
|
let delegate = self.table.get(&delegate)?;
|
||||||
|
Ok(delegate.worktree_id())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn root_path(
|
||||||
|
&mut self,
|
||||||
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
|
) -> wasmtime::Result<String> {
|
||||||
|
let delegate = self.table.get(&delegate)?;
|
||||||
|
Ok(delegate.worktree_root_path().to_string_lossy().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_text_file(
|
||||||
|
&mut self,
|
||||||
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
|
path: String,
|
||||||
|
) -> wasmtime::Result<Result<String, String>> {
|
||||||
|
let delegate = self.table.get(&delegate)?;
|
||||||
|
Ok(delegate
|
||||||
|
.read_text_file(path.into())
|
||||||
|
.await
|
||||||
|
.map_err(|error| error.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn shell_env(
|
||||||
|
&mut self,
|
||||||
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
|
) -> wasmtime::Result<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<Worktree>) -> Result<()> {
|
||||||
|
// We only ever hand out borrows of worktrees.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl nodejs::Host for WasmState {
|
||||||
|
async fn node_binary_path(&mut self) -> wasmtime::Result<Result<String, String>> {
|
||||||
|
self.host
|
||||||
|
.node_runtime
|
||||||
|
.binary_path()
|
||||||
|
.await
|
||||||
|
.map(|path| path.to_string_lossy().to_string())
|
||||||
|
.to_wasmtime_result()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn npm_package_latest_version(
|
||||||
|
&mut self,
|
||||||
|
package_name: String,
|
||||||
|
) -> wasmtime::Result<Result<String, String>> {
|
||||||
|
self.host
|
||||||
|
.node_runtime
|
||||||
|
.npm_package_latest_version(&package_name)
|
||||||
|
.await
|
||||||
|
.to_wasmtime_result()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn npm_package_installed_version(
|
||||||
|
&mut self,
|
||||||
|
package_name: String,
|
||||||
|
) -> wasmtime::Result<Result<Option<String>, String>> {
|
||||||
|
self.host
|
||||||
|
.node_runtime
|
||||||
|
.npm_package_installed_version(&self.work_dir(), &package_name)
|
||||||
|
.await
|
||||||
|
.to_wasmtime_result()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn npm_install_package(
|
||||||
|
&mut self,
|
||||||
|
package_name: String,
|
||||||
|
version: String,
|
||||||
|
) -> wasmtime::Result<Result<(), String>> {
|
||||||
|
self.host
|
||||||
|
.node_runtime
|
||||||
|
.npm_install_packages(&self.work_dir(), &[(&package_name, &version)])
|
||||||
|
.await
|
||||||
|
.to_wasmtime_result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl lsp::Host for WasmState {}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl github::Host for WasmState {
|
||||||
|
async fn latest_github_release(
|
||||||
|
&mut self,
|
||||||
|
repo: String,
|
||||||
|
options: github::GithubReleaseOptions,
|
||||||
|
) -> wasmtime::Result<Result<github::GithubRelease, String>> {
|
||||||
|
maybe!(async {
|
||||||
|
let release = http::github::latest_github_release(
|
||||||
|
&repo,
|
||||||
|
options.require_assets,
|
||||||
|
options.pre_release,
|
||||||
|
self.host.http_client.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(github::GithubRelease {
|
||||||
|
version: release.tag_name,
|
||||||
|
assets: release
|
||||||
|
.assets
|
||||||
|
.into_iter()
|
||||||
|
.map(|asset| github::GithubReleaseAsset {
|
||||||
|
name: asset.name,
|
||||||
|
download_url: asset.browser_download_url,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.to_wasmtime_result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl platform::Host for WasmState {
|
||||||
|
async fn current_platform(&mut self) -> Result<(platform::Os, platform::Architecture)> {
|
||||||
|
Ok((
|
||||||
|
match env::consts::OS {
|
||||||
|
"macos" => platform::Os::Mac,
|
||||||
|
"linux" => platform::Os::Linux,
|
||||||
|
"windows" => platform::Os::Windows,
|
||||||
|
_ => panic!("unsupported os"),
|
||||||
|
},
|
||||||
|
match env::consts::ARCH {
|
||||||
|
"aarch64" => platform::Architecture::Aarch64,
|
||||||
|
"x86" => platform::Architecture::X86,
|
||||||
|
"x86_64" => platform::Architecture::X8664,
|
||||||
|
_ => panic!("unsupported architecture"),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ExtensionImports for WasmState {
|
||||||
|
async fn get_settings(
|
||||||
|
&mut self,
|
||||||
|
location: Option<self::SettingsLocation>,
|
||||||
|
category: String,
|
||||||
|
key: Option<String>,
|
||||||
|
) -> wasmtime::Result<Result<String, String>> {
|
||||||
|
self.on_main_thread(|cx| {
|
||||||
|
async move {
|
||||||
|
let location = location
|
||||||
|
.as_ref()
|
||||||
|
.map(|location| ::settings::SettingsLocation {
|
||||||
|
worktree_id: location.worktree_id as usize,
|
||||||
|
path: Path::new(&location.path),
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.update(|cx| match category.as_str() {
|
||||||
|
"language" => {
|
||||||
|
let settings =
|
||||||
|
AllLanguageSettings::get(location, cx).language(key.as_deref());
|
||||||
|
Ok(serde_json::to_string(&settings::LanguageSettings {
|
||||||
|
tab_size: settings.tab_size,
|
||||||
|
})?)
|
||||||
|
}
|
||||||
|
"lsp" => {
|
||||||
|
let settings = key
|
||||||
|
.and_then(|key| {
|
||||||
|
ProjectSettings::get(location, cx)
|
||||||
|
.lsp
|
||||||
|
.get(&Arc::<str>::from(key))
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
Ok(serde_json::to_string(&settings::LspSettings {
|
||||||
|
binary: settings.binary.map(|binary| settings::BinarySettings {
|
||||||
|
path: binary.path,
|
||||||
|
arguments: binary.arguments,
|
||||||
|
}),
|
||||||
|
settings: settings.settings,
|
||||||
|
initialization_options: settings.initialization_options,
|
||||||
|
})?)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
bail!("Unknown settings category: {}", category);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.boxed_local()
|
||||||
|
})
|
||||||
|
.await?
|
||||||
|
.to_wasmtime_result()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_language_server_installation_status(
|
||||||
|
&mut self,
|
||||||
|
server_name: String,
|
||||||
|
status: LanguageServerInstallationStatus,
|
||||||
|
) -> wasmtime::Result<()> {
|
||||||
|
let status = match status {
|
||||||
|
LanguageServerInstallationStatus::CheckingForUpdate => {
|
||||||
|
LanguageServerBinaryStatus::CheckingForUpdate
|
||||||
|
}
|
||||||
|
LanguageServerInstallationStatus::Downloading => {
|
||||||
|
LanguageServerBinaryStatus::Downloading
|
||||||
|
}
|
||||||
|
LanguageServerInstallationStatus::None => LanguageServerBinaryStatus::None,
|
||||||
|
LanguageServerInstallationStatus::Failed(error) => {
|
||||||
|
LanguageServerBinaryStatus::Failed { error }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.host
|
||||||
|
.language_registry
|
||||||
|
.update_lsp_status(language::LanguageServerName(server_name.into()), status);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn download_file(
|
||||||
|
&mut self,
|
||||||
|
url: String,
|
||||||
|
path: String,
|
||||||
|
file_type: DownloadedFileType,
|
||||||
|
) -> wasmtime::Result<Result<(), String>> {
|
||||||
|
maybe!(async {
|
||||||
|
let path = PathBuf::from(path);
|
||||||
|
let extension_work_dir = self.host.work_dir.join(self.manifest.id.as_ref());
|
||||||
|
|
||||||
|
self.host.fs.create_dir(&extension_work_dir).await?;
|
||||||
|
|
||||||
|
let destination_path = self
|
||||||
|
.host
|
||||||
|
.writeable_path_from_extension(&self.manifest.id, &path)?;
|
||||||
|
|
||||||
|
let mut response = self
|
||||||
|
.host
|
||||||
|
.http_client
|
||||||
|
.get(&url, Default::default(), true)
|
||||||
|
.await
|
||||||
|
.map_err(|err| anyhow!("error downloading release: {}", err))?;
|
||||||
|
|
||||||
|
if !response.status().is_success() {
|
||||||
|
Err(anyhow!(
|
||||||
|
"download failed with status {}",
|
||||||
|
response.status().to_string()
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
let body = BufReader::new(response.body_mut());
|
||||||
|
|
||||||
|
match file_type {
|
||||||
|
DownloadedFileType::Uncompressed => {
|
||||||
|
futures::pin_mut!(body);
|
||||||
|
self.host
|
||||||
|
.fs
|
||||||
|
.create_file_with(&destination_path, body)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
DownloadedFileType::Gzip => {
|
||||||
|
let body = GzipDecoder::new(body);
|
||||||
|
futures::pin_mut!(body);
|
||||||
|
self.host
|
||||||
|
.fs
|
||||||
|
.create_file_with(&destination_path, body)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
DownloadedFileType::GzipTar => {
|
||||||
|
let body = GzipDecoder::new(body);
|
||||||
|
futures::pin_mut!(body);
|
||||||
|
self.host
|
||||||
|
.fs
|
||||||
|
.extract_tar_file(&destination_path, Archive::new(body))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
DownloadedFileType::Zip => {
|
||||||
|
let file_name = destination_path
|
||||||
|
.file_name()
|
||||||
|
.ok_or_else(|| anyhow!("invalid download path"))?
|
||||||
|
.to_string_lossy();
|
||||||
|
let zip_filename = format!("{file_name}.zip");
|
||||||
|
let mut zip_path = destination_path.clone();
|
||||||
|
zip_path.set_file_name(zip_filename);
|
||||||
|
|
||||||
|
futures::pin_mut!(body);
|
||||||
|
self.host.fs.create_file_with(&zip_path, body).await?;
|
||||||
|
|
||||||
|
let unzip_status = std::process::Command::new("unzip")
|
||||||
|
.current_dir(&extension_work_dir)
|
||||||
|
.arg("-d")
|
||||||
|
.arg(&destination_path)
|
||||||
|
.arg(&zip_path)
|
||||||
|
.output()?
|
||||||
|
.status;
|
||||||
|
if !unzip_status.success() {
|
||||||
|
Err(anyhow!("failed to unzip {} archive", path.display()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.to_wasmtime_result()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn make_file_executable(&mut self, path: String) -> wasmtime::Result<Result<(), String>> {
|
||||||
|
#[allow(unused)]
|
||||||
|
let path = self
|
||||||
|
.host
|
||||||
|
.writeable_path_from_extension(&self.manifest.id, Path::new(&path))?;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::fs::{self, Permissions};
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|
||||||
|
return fs::set_permissions(&path, Permissions::from_mode(0o755))
|
||||||
|
.map_err(|error| anyhow!("failed to set permissions for path {path:?}: {error}"))
|
||||||
|
.to_wasmtime_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
Ok(Ok(()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "zed_extension_api"
|
name = "zed_extension_api"
|
||||||
version = "0.0.6"
|
version = "0.0.7"
|
||||||
description = "APIs for creating Zed extensions in Rust"
|
description = "APIs for creating Zed extensions in Rust"
|
||||||
repository = "https://github.com/zed-industries/zed"
|
repository = "https://github.com/zed-industries/zed"
|
||||||
documentation = "https://docs.rs/zed_extension_api"
|
documentation = "https://docs.rs/zed_extension_api"
|
||||||
|
|
|
@ -140,7 +140,7 @@ pub static ZED_API_VERSION: [u8; 6] = *include_bytes!(concat!(env!("OUT_DIR"), "
|
||||||
mod wit {
|
mod wit {
|
||||||
wit_bindgen::generate!({
|
wit_bindgen::generate!({
|
||||||
skip: ["init-extension"],
|
skip: ["init-extension"],
|
||||||
path: "./wit/since_v0.0.6",
|
path: "./wit/since_v0.0.7",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#[path = "../wit/since_v0.0.6/settings.rs"]
|
#[path = "../wit/since_v0.0.7/settings.rs"]
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
use crate::{wit, Result, SettingsLocation, Worktree};
|
use crate::{wit, Result, SettingsLocation, Worktree};
|
||||||
|
|
130
crates/extension_api/wit/since_v0.0.7/extension.wit
Normal file
130
crates/extension_api/wit/since_v0.0.7/extension.wit
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
package zed:extension;
|
||||||
|
|
||||||
|
world extension {
|
||||||
|
import github;
|
||||||
|
import platform;
|
||||||
|
import nodejs;
|
||||||
|
|
||||||
|
use lsp.{completion, symbol};
|
||||||
|
|
||||||
|
/// Initializes the extension.
|
||||||
|
export init-extension: func();
|
||||||
|
|
||||||
|
/// The type of a downloaded file.
|
||||||
|
enum downloaded-file-type {
|
||||||
|
/// A gzipped file (`.gz`).
|
||||||
|
gzip,
|
||||||
|
/// A gzipped tar archive (`.tar.gz`).
|
||||||
|
gzip-tar,
|
||||||
|
/// A ZIP file (`.zip`).
|
||||||
|
zip,
|
||||||
|
/// An uncompressed file.
|
||||||
|
uncompressed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The installation status for a language server.
|
||||||
|
variant language-server-installation-status {
|
||||||
|
/// The language server has no installation status.
|
||||||
|
none,
|
||||||
|
/// The language server is being downloaded.
|
||||||
|
downloading,
|
||||||
|
/// The language server is checking for updates.
|
||||||
|
checking-for-update,
|
||||||
|
/// The language server installation failed for specified reason.
|
||||||
|
failed(string),
|
||||||
|
}
|
||||||
|
|
||||||
|
record settings-location {
|
||||||
|
worktree-id: u64,
|
||||||
|
path: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
import get-settings: func(path: option<settings-location>, category: string, key: option<string>) -> result<string, string>;
|
||||||
|
|
||||||
|
/// Downloads a file from the given URL and saves it to the given path within the extension's
|
||||||
|
/// working directory.
|
||||||
|
///
|
||||||
|
/// The file will be extracted according to the given file type.
|
||||||
|
import download-file: func(url: string, file-path: string, file-type: downloaded-file-type) -> result<_, string>;
|
||||||
|
|
||||||
|
/// Makes the file at the given path executable.
|
||||||
|
import make-file-executable: func(filepath: string) -> result<_, string>;
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
/// A list of environment variables.
|
||||||
|
type env-vars = list<tuple<string, string>>;
|
||||||
|
|
||||||
|
/// A command.
|
||||||
|
record command {
|
||||||
|
/// The command to execute.
|
||||||
|
command: string,
|
||||||
|
/// The arguments to pass to the command.
|
||||||
|
args: list<string>,
|
||||||
|
/// The environment variables to set for the command.
|
||||||
|
env: env-vars,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Zed worktree.
|
||||||
|
resource worktree {
|
||||||
|
/// Returns the ID of the worktree.
|
||||||
|
id: func() -> u64;
|
||||||
|
/// Returns the root path of the worktree.
|
||||||
|
root-path: func() -> string;
|
||||||
|
/// Returns the textual contents of the specified file in the worktree.
|
||||||
|
read-text-file: func(path: string) -> result<string, string>;
|
||||||
|
/// Returns the path to the given binary name, if one is present on the `$PATH`.
|
||||||
|
which: func(binary-name: string) -> option<string>;
|
||||||
|
/// Returns the current shell environment.
|
||||||
|
shell-env: func() -> env-vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the command used to start up the language server.
|
||||||
|
export language-server-command: func(language-server-id: string, worktree: borrow<worktree>) -> result<command, string>;
|
||||||
|
|
||||||
|
/// Returns the initialization options to pass to the language server on startup.
|
||||||
|
///
|
||||||
|
/// The initialization options are represented as a JSON string.
|
||||||
|
export language-server-initialization-options: func(language-server-id: string, worktree: borrow<worktree>) -> result<option<string>, string>;
|
||||||
|
|
||||||
|
/// Returns the workspace configuration options to pass to the language server.
|
||||||
|
export language-server-workspace-configuration: func(language-server-id: string, worktree: borrow<worktree>) -> result<option<string>, string>;
|
||||||
|
|
||||||
|
/// A label containing some code.
|
||||||
|
record code-label {
|
||||||
|
/// The source code to parse with Tree-sitter.
|
||||||
|
code: string,
|
||||||
|
/// The spans to display in the label.
|
||||||
|
spans: list<code-label-span>,
|
||||||
|
/// The range of the displayed label to include when filtering.
|
||||||
|
filter-range: range,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A span within a code label.
|
||||||
|
variant code-label-span {
|
||||||
|
/// A range into the parsed code.
|
||||||
|
code-range(range),
|
||||||
|
/// A span containing a code literal.
|
||||||
|
literal(code-label-span-literal),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A span containing a code literal.
|
||||||
|
record code-label-span-literal {
|
||||||
|
/// The literal text.
|
||||||
|
text: string,
|
||||||
|
/// The name of the highlight to use for this literal.
|
||||||
|
highlight-name: option<string>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A (half-open) range (`[start, end)`).
|
||||||
|
record range {
|
||||||
|
/// The start of the range (inclusive).
|
||||||
|
start: u32,
|
||||||
|
/// The end of the range (exclusive).
|
||||||
|
end: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
export labels-for-completions: func(language-server-id: string, completions: list<completion>) -> result<list<option<code-label>>, string>;
|
||||||
|
export labels-for-symbols: func(language-server-id: string, symbols: list<symbol>) -> result<list<option<code-label>>, string>;
|
||||||
|
}
|
28
crates/extension_api/wit/since_v0.0.7/github.wit
Normal file
28
crates/extension_api/wit/since_v0.0.7/github.wit
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
interface github {
|
||||||
|
/// A GitHub release.
|
||||||
|
record github-release {
|
||||||
|
/// The version of the release.
|
||||||
|
version: string,
|
||||||
|
/// The list of assets attached to the release.
|
||||||
|
assets: list<github-release-asset>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An asset from a GitHub release.
|
||||||
|
record github-release-asset {
|
||||||
|
/// The name of the asset.
|
||||||
|
name: string,
|
||||||
|
/// The download URL for the asset.
|
||||||
|
download-url: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The options used to filter down GitHub releases.
|
||||||
|
record github-release-options {
|
||||||
|
/// Whether releases without assets should be included.
|
||||||
|
require-assets: bool,
|
||||||
|
/// Whether pre-releases should be included.
|
||||||
|
pre-release: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the latest release for the given GitHub repository.
|
||||||
|
latest-github-release: func(repo: string, options: github-release-options) -> result<github-release, string>;
|
||||||
|
}
|
83
crates/extension_api/wit/since_v0.0.7/lsp.wit
Normal file
83
crates/extension_api/wit/since_v0.0.7/lsp.wit
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
interface lsp {
|
||||||
|
/// An LSP completion.
|
||||||
|
record completion {
|
||||||
|
label: string,
|
||||||
|
detail: option<string>,
|
||||||
|
kind: option<completion-kind>,
|
||||||
|
insert-text-format: option<insert-text-format>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of an LSP completion.
|
||||||
|
variant completion-kind {
|
||||||
|
text,
|
||||||
|
method,
|
||||||
|
function,
|
||||||
|
%constructor,
|
||||||
|
field,
|
||||||
|
variable,
|
||||||
|
class,
|
||||||
|
%interface,
|
||||||
|
module,
|
||||||
|
property,
|
||||||
|
unit,
|
||||||
|
value,
|
||||||
|
%enum,
|
||||||
|
keyword,
|
||||||
|
snippet,
|
||||||
|
color,
|
||||||
|
file,
|
||||||
|
reference,
|
||||||
|
folder,
|
||||||
|
enum-member,
|
||||||
|
constant,
|
||||||
|
struct,
|
||||||
|
event,
|
||||||
|
operator,
|
||||||
|
type-parameter,
|
||||||
|
other(s32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines how to interpret the insert text in a completion item.
|
||||||
|
variant insert-text-format {
|
||||||
|
plain-text,
|
||||||
|
snippet,
|
||||||
|
other(s32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An LSP symbol.
|
||||||
|
record symbol {
|
||||||
|
kind: symbol-kind,
|
||||||
|
name: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of an LSP symbol.
|
||||||
|
variant symbol-kind {
|
||||||
|
file,
|
||||||
|
module,
|
||||||
|
namespace,
|
||||||
|
%package,
|
||||||
|
class,
|
||||||
|
method,
|
||||||
|
property,
|
||||||
|
field,
|
||||||
|
%constructor,
|
||||||
|
%enum,
|
||||||
|
%interface,
|
||||||
|
function,
|
||||||
|
variable,
|
||||||
|
constant,
|
||||||
|
%string,
|
||||||
|
number,
|
||||||
|
boolean,
|
||||||
|
array,
|
||||||
|
object,
|
||||||
|
key,
|
||||||
|
null,
|
||||||
|
enum-member,
|
||||||
|
struct,
|
||||||
|
event,
|
||||||
|
operator,
|
||||||
|
type-parameter,
|
||||||
|
other(s32),
|
||||||
|
}
|
||||||
|
}
|
13
crates/extension_api/wit/since_v0.0.7/nodejs.wit
Normal file
13
crates/extension_api/wit/since_v0.0.7/nodejs.wit
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
interface nodejs {
|
||||||
|
/// Returns the path to the Node binary used by Zed.
|
||||||
|
node-binary-path: func() -> result<string, string>;
|
||||||
|
|
||||||
|
/// Returns the latest version of the given NPM package.
|
||||||
|
npm-package-latest-version: func(package-name: string) -> result<string, string>;
|
||||||
|
|
||||||
|
/// Returns the installed version of the given NPM package, if it exists.
|
||||||
|
npm-package-installed-version: func(package-name: string) -> result<option<string>, string>;
|
||||||
|
|
||||||
|
/// Installs the specified NPM package.
|
||||||
|
npm-install-package: func(package-name: string, version: string) -> result<_, string>;
|
||||||
|
}
|
24
crates/extension_api/wit/since_v0.0.7/platform.wit
Normal file
24
crates/extension_api/wit/since_v0.0.7/platform.wit
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
interface platform {
|
||||||
|
/// An operating system.
|
||||||
|
enum os {
|
||||||
|
/// macOS.
|
||||||
|
mac,
|
||||||
|
/// Linux.
|
||||||
|
linux,
|
||||||
|
/// Windows.
|
||||||
|
windows,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A platform architecture.
|
||||||
|
enum architecture {
|
||||||
|
/// AArch64 (e.g., Apple Silicon).
|
||||||
|
aarch64,
|
||||||
|
/// x86.
|
||||||
|
x86,
|
||||||
|
/// x86-64.
|
||||||
|
x8664,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the current operating system and architecture.
|
||||||
|
current-platform: func() -> tuple<os, architecture>;
|
||||||
|
}
|
29
crates/extension_api/wit/since_v0.0.7/settings.rs
Normal file
29
crates/extension_api/wit/since_v0.0.7/settings.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
|
/// The settings for a particular language.
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct LanguageSettings {
|
||||||
|
/// How many columns a tab should occupy.
|
||||||
|
pub tab_size: NonZeroU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The settings for a particular language server.
|
||||||
|
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct LspSettings {
|
||||||
|
/// The settings for the language server binary.
|
||||||
|
pub binary: Option<BinarySettings>,
|
||||||
|
/// The initialization options to pass to the language server.
|
||||||
|
pub initialization_options: Option<serde_json::Value>,
|
||||||
|
/// The settings to pass to language server.
|
||||||
|
pub settings: Option<serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The settings for a language server binary.
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct BinarySettings {
|
||||||
|
/// The path to the binary.
|
||||||
|
pub path: Option<String>,
|
||||||
|
/// The arguments to pass to the binary.
|
||||||
|
pub arguments: Option<Vec<String>>,
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue