mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
Add language_server_workspace_configuration
to extension API (#10212)
This PR adds the ability for extensions to implement `language_server_workspace_configuration` to provide workspace configuration to the language server. We've used the Dart extension as a motivating example for this, pulling it out into an extension in the process. Release Notes: - Removed built-in support for Dart, in favor of making it available as an extension. The Dart extension will be suggested for download when you open a `.dart` file. --------- Co-authored-by: Max <max@zed.dev> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
4aaf3459c4
commit
c851e6edba
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -5338,7 +5338,6 @@ dependencies = [
|
|||||||
"tree-sitter-c",
|
"tree-sitter-c",
|
||||||
"tree-sitter-cpp",
|
"tree-sitter-cpp",
|
||||||
"tree-sitter-css",
|
"tree-sitter-css",
|
||||||
"tree-sitter-dart",
|
|
||||||
"tree-sitter-elixir",
|
"tree-sitter-elixir",
|
||||||
"tree-sitter-elm",
|
"tree-sitter-elm",
|
||||||
"tree-sitter-embedded-template",
|
"tree-sitter-embedded-template",
|
||||||
@ -10217,15 +10216,6 @@ dependencies = [
|
|||||||
"tree-sitter",
|
"tree-sitter",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tree-sitter-dart"
|
|
||||||
version = "0.0.1"
|
|
||||||
source = "git+https://github.com/agent3bood/tree-sitter-dart?rev=48934e3bf757a9b78f17bdfaa3e2b4284656fdc7#48934e3bf757a9b78f17bdfaa3e2b4284656fdc7"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"tree-sitter",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tree-sitter-elixir"
|
name = "tree-sitter-elixir"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -12490,6 +12480,13 @@ dependencies = [
|
|||||||
"zed_extension_api 0.0.4",
|
"zed_extension_api 0.0.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zed_dart"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"zed_extension_api 0.0.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_emmet"
|
name = "zed_emmet"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
@ -12526,6 +12523,8 @@ dependencies = [
|
|||||||
name = "zed_extension_api"
|
name = "zed_extension_api"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"wit-bindgen",
|
"wit-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -12575,7 +12574,7 @@ dependencies = [
|
|||||||
name = "zed_svelte"
|
name = "zed_svelte"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zed_extension_api 0.0.4",
|
"zed_extension_api 0.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -102,6 +102,7 @@ members = [
|
|||||||
"extensions/astro",
|
"extensions/astro",
|
||||||
"extensions/clojure",
|
"extensions/clojure",
|
||||||
"extensions/csharp",
|
"extensions/csharp",
|
||||||
|
"extensions/dart",
|
||||||
"extensions/emmet",
|
"extensions/emmet",
|
||||||
"extensions/erlang",
|
"extensions/erlang",
|
||||||
"extensions/gleam",
|
"extensions/gleam",
|
||||||
@ -308,7 +309,6 @@ tree-sitter-bash = { git = "https://github.com/tree-sitter/tree-sitter-bash", re
|
|||||||
tree-sitter-c = "0.20.1"
|
tree-sitter-c = "0.20.1"
|
||||||
tree-sitter-cpp = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev = "f44509141e7e483323d2ec178f2d2e6c0fc041c1" }
|
tree-sitter-cpp = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev = "f44509141e7e483323d2ec178f2d2e6c0fc041c1" }
|
||||||
tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" }
|
tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" }
|
||||||
tree-sitter-dart = { git = "https://github.com/agent3bood/tree-sitter-dart", rev = "48934e3bf757a9b78f17bdfaa3e2b4284656fdc7" }
|
|
||||||
tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "a2861e88a730287a60c11ea9299c033c7d076e30" }
|
tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "a2861e88a730287a60c11ea9299c033c7d076e30" }
|
||||||
tree-sitter-elm = { git = "https://github.com/elm-tooling/tree-sitter-elm", rev = "692c50c0b961364c40299e73c1306aecb5d20f40" }
|
tree-sitter-elm = { git = "https://github.com/elm-tooling/tree-sitter-elm", rev = "692c50c0b961364c40299e73c1306aecb5d20f40" }
|
||||||
tree-sitter-embedded-template = "0.20.0"
|
tree-sitter-embedded-template = "0.20.0"
|
||||||
|
@ -12,6 +12,7 @@ use language::{
|
|||||||
};
|
};
|
||||||
use lsp::LanguageServerBinary;
|
use lsp::LanguageServerBinary;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use serde_json::Value;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
@ -181,6 +182,42 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn workspace_configuration(
|
||||||
|
self: Arc<Self>,
|
||||||
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
|
_cx: &mut AsyncAppContext,
|
||||||
|
) -> Result<Value> {
|
||||||
|
let delegate = delegate.clone();
|
||||||
|
let json_options: Option<String> = self
|
||||||
|
.extension
|
||||||
|
.call({
|
||||||
|
let this = self.clone();
|
||||||
|
|extension, store| {
|
||||||
|
async move {
|
||||||
|
let resource = store.data_mut().table().push(delegate)?;
|
||||||
|
let options = extension
|
||||||
|
.call_language_server_workspace_configuration(
|
||||||
|
store,
|
||||||
|
&this.language_server_id,
|
||||||
|
resource,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.map_err(|e| anyhow!("{}", e))?;
|
||||||
|
anyhow::Ok(options)
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
Ok(if let Some(json_options) = json_options {
|
||||||
|
serde_json::from_str(&json_options).with_context(|| {
|
||||||
|
format!("failed to parse initialization_options from extension: {json_options}")
|
||||||
|
})?
|
||||||
|
} else {
|
||||||
|
serde_json::json!({})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async fn labels_for_completions(
|
async fn labels_for_completions(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
completions: &[lsp::CompletionItem],
|
completions: &[lsp::CompletionItem],
|
||||||
|
@ -237,6 +237,7 @@ impl ExtensionStore {
|
|||||||
node_runtime,
|
node_runtime,
|
||||||
language_registry.clone(),
|
language_registry.clone(),
|
||||||
work_dir,
|
work_dir,
|
||||||
|
cx,
|
||||||
),
|
),
|
||||||
wasm_extensions: Vec::new(),
|
wasm_extensions: Vec::new(),
|
||||||
fs,
|
fs,
|
||||||
|
@ -3,6 +3,7 @@ pub(crate) mod wit;
|
|||||||
use crate::ExtensionManifest;
|
use crate::ExtensionManifest;
|
||||||
use anyhow::{anyhow, bail, Context as _, Result};
|
use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
use fs::{normalize_path, Fs};
|
use fs::{normalize_path, Fs};
|
||||||
|
use futures::future::LocalBoxFuture;
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::{
|
channel::{
|
||||||
mpsc::{self, UnboundedSender},
|
mpsc::{self, UnboundedSender},
|
||||||
@ -11,7 +12,7 @@ use futures::{
|
|||||||
future::BoxFuture,
|
future::BoxFuture,
|
||||||
Future, FutureExt, StreamExt as _,
|
Future, FutureExt, StreamExt as _,
|
||||||
};
|
};
|
||||||
use gpui::BackgroundExecutor;
|
use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
|
||||||
use language::LanguageRegistry;
|
use language::LanguageRegistry;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
@ -34,6 +35,8 @@ pub(crate) struct WasmHost {
|
|||||||
pub(crate) language_registry: Arc<LanguageRegistry>,
|
pub(crate) language_registry: Arc<LanguageRegistry>,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
pub(crate) work_dir: PathBuf,
|
pub(crate) work_dir: PathBuf,
|
||||||
|
_main_thread_message_task: Task<()>,
|
||||||
|
main_thread_message_tx: mpsc::UnboundedSender<MainThreadCall>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -51,6 +54,9 @@ pub(crate) struct WasmState {
|
|||||||
pub(crate) host: Arc<WasmHost>,
|
pub(crate) host: Arc<WasmHost>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MainThreadCall =
|
||||||
|
Box<dyn Send + for<'a> FnOnce(&'a mut AsyncAppContext) -> LocalBoxFuture<'a, ()>>;
|
||||||
|
|
||||||
type ExtensionCall = Box<
|
type ExtensionCall = Box<
|
||||||
dyn Send + for<'a> FnOnce(&'a mut Extension, &'a mut Store<WasmState>) -> BoxFuture<'a, ()>,
|
dyn Send + for<'a> FnOnce(&'a mut Extension, &'a mut Store<WasmState>) -> BoxFuture<'a, ()>,
|
||||||
>;
|
>;
|
||||||
@ -75,7 +81,14 @@ impl WasmHost {
|
|||||||
node_runtime: Arc<dyn NodeRuntime>,
|
node_runtime: Arc<dyn NodeRuntime>,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Arc<LanguageRegistry>,
|
||||||
work_dir: PathBuf,
|
work_dir: PathBuf,
|
||||||
|
cx: &mut AppContext,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
|
let (tx, mut rx) = mpsc::unbounded::<MainThreadCall>();
|
||||||
|
let task = cx.spawn(|mut cx| async move {
|
||||||
|
while let Some(message) = rx.next().await {
|
||||||
|
message(&mut cx).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
Arc::new(Self {
|
Arc::new(Self {
|
||||||
engine: wasm_engine(),
|
engine: wasm_engine(),
|
||||||
fs,
|
fs,
|
||||||
@ -83,6 +96,8 @@ impl WasmHost {
|
|||||||
http_client,
|
http_client,
|
||||||
node_runtime,
|
node_runtime,
|
||||||
language_registry,
|
language_registry,
|
||||||
|
_main_thread_message_task: task,
|
||||||
|
main_thread_message_tx: tx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +253,26 @@ impl WasmExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WasmState {
|
impl WasmState {
|
||||||
|
fn on_main_thread<T, Fn>(&self, f: Fn) -> impl 'static + Future<Output = T>
|
||||||
|
where
|
||||||
|
T: 'static + Send,
|
||||||
|
Fn: 'static + Send + for<'a> FnOnce(&'a mut AsyncAppContext) -> LocalBoxFuture<'a, T>,
|
||||||
|
{
|
||||||
|
let (return_tx, return_rx) = oneshot::channel();
|
||||||
|
self.host
|
||||||
|
.main_thread_message_tx
|
||||||
|
.clone()
|
||||||
|
.unbounded_send(Box::new(move |cx| {
|
||||||
|
async {
|
||||||
|
let result = f(cx).await;
|
||||||
|
return_tx.send(result).ok();
|
||||||
|
}
|
||||||
|
.boxed_local()
|
||||||
|
}))
|
||||||
|
.expect("main thread message channel should not be closed yet");
|
||||||
|
async move { return_rx.await.expect("main thread message channel") }
|
||||||
|
}
|
||||||
|
|
||||||
fn work_dir(&self) -> PathBuf {
|
fn work_dir(&self) -> PathBuf {
|
||||||
self.host.work_dir.join(self.manifest.id.as_ref())
|
self.host.work_dir.join(self.manifest.id.as_ref())
|
||||||
}
|
}
|
||||||
|
@ -148,6 +148,25 @@ impl Extension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn call_language_server_workspace_configuration(
|
||||||
|
&self,
|
||||||
|
store: &mut Store<WasmState>,
|
||||||
|
language_server_id: &LanguageServerName,
|
||||||
|
resource: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
|
) -> Result<Result<Option<String>, String>> {
|
||||||
|
match self {
|
||||||
|
Extension::V006(ext) => {
|
||||||
|
ext.call_language_server_workspace_configuration(
|
||||||
|
store,
|
||||||
|
&language_server_id.0,
|
||||||
|
resource,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Extension::V004(_) | Extension::V001(_) => Ok(Ok(None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn call_labels_for_completions(
|
pub async fn call_labels_for_completions(
|
||||||
&self,
|
&self,
|
||||||
store: &mut Store<WasmState>,
|
store: &mut Store<WasmState>,
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
use crate::wasm_host::wit::ToWasmtimeResult;
|
use crate::wasm_host::wit::ToWasmtimeResult;
|
||||||
use crate::wasm_host::WasmState;
|
use crate::wasm_host::WasmState;
|
||||||
use anyhow::{anyhow, Result};
|
use ::settings::Settings;
|
||||||
|
use anyhow::{anyhow, bail, 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 futures::io::BufReader;
|
use futures::{io::BufReader, FutureExt as _};
|
||||||
|
use language::language_settings::AllLanguageSettings;
|
||||||
use language::{LanguageServerBinaryStatus, LspAdapterDelegate};
|
use language::{LanguageServerBinaryStatus, LspAdapterDelegate};
|
||||||
|
use project::project_settings::ProjectSettings;
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
use std::path::Path;
|
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
path::PathBuf,
|
path::{Path, PathBuf},
|
||||||
sync::{Arc, OnceLock},
|
sync::{Arc, OnceLock},
|
||||||
};
|
};
|
||||||
use util::maybe;
|
use util::maybe;
|
||||||
@ -27,6 +29,10 @@ wasmtime::component::bindgen!({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mod settings {
|
||||||
|
include!("../../../../extension_api/wit/since_v0.0.6/settings.rs");
|
||||||
|
}
|
||||||
|
|
||||||
pub type ExtensionWorktree = Arc<dyn LspAdapterDelegate>;
|
pub type ExtensionWorktree = Arc<dyn LspAdapterDelegate>;
|
||||||
|
|
||||||
pub fn linker() -> &'static Linker<WasmState> {
|
pub fn linker() -> &'static Linker<WasmState> {
|
||||||
@ -36,6 +42,22 @@ pub fn linker() -> &'static Linker<WasmState> {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl HostWorktree for WasmState {
|
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(
|
async fn read_text_file(
|
||||||
&mut self,
|
&mut self,
|
||||||
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
delegate: Resource<Arc<dyn LspAdapterDelegate>>,
|
||||||
@ -78,6 +100,58 @@ impl self::zed::extension::lsp::Host for WasmState {}
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl ExtensionImports for WasmState {
|
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_global(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 node_binary_path(&mut self) -> wasmtime::Result<Result<String, String>> {
|
async fn node_binary_path(&mut self) -> wasmtime::Result<Result<String, String>> {
|
||||||
self.host
|
self.host
|
||||||
.node_runtime
|
.node_runtime
|
||||||
|
@ -15,6 +15,8 @@ workspace = true
|
|||||||
path = "src/extension_api.rs"
|
path = "src/extension_api.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
wit-bindgen = "0.22"
|
wit-bindgen = "0.22"
|
||||||
|
|
||||||
[package.metadata.component]
|
[package.metadata.component]
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
//! The Zed Rust Extension API allows you write extensions for [Zed](https://zed.dev/) in Rust.
|
//! The Zed Rust Extension API allows you write extensions for [Zed](https://zed.dev/) in Rust.
|
||||||
|
|
||||||
|
pub mod settings;
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use wit::*;
|
use wit::*;
|
||||||
|
|
||||||
|
pub use serde_json;
|
||||||
|
|
||||||
// WIT re-exports.
|
// WIT re-exports.
|
||||||
//
|
//
|
||||||
// We explicitly enumerate the symbols we want to re-export, as there are some
|
// We explicitly enumerate the symbols we want to re-export, as there are some
|
||||||
@ -62,7 +66,16 @@ pub trait Extension: Send + Sync {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_language_server_id: &LanguageServerId,
|
_language_server_id: &LanguageServerId,
|
||||||
_worktree: &Worktree,
|
_worktree: &Worktree,
|
||||||
) -> Result<Option<String>> {
|
) -> Result<Option<serde_json::Value>> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the workspace configuration options to pass to the language server.
|
||||||
|
fn language_server_workspace_configuration(
|
||||||
|
&mut self,
|
||||||
|
_language_server_id: &LanguageServerId,
|
||||||
|
_worktree: &Worktree,
|
||||||
|
) -> Result<Option<serde_json::Value>> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +155,19 @@ impl wit::Guest for Component {
|
|||||||
worktree: &Worktree,
|
worktree: &Worktree,
|
||||||
) -> Result<Option<String>, String> {
|
) -> Result<Option<String>, String> {
|
||||||
let language_server_id = LanguageServerId(language_server_id);
|
let language_server_id = LanguageServerId(language_server_id);
|
||||||
extension().language_server_initialization_options(&language_server_id, worktree)
|
Ok(extension()
|
||||||
|
.language_server_initialization_options(&language_server_id, worktree)?
|
||||||
|
.and_then(|value| serde_json::to_string(&value).ok()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn language_server_workspace_configuration(
|
||||||
|
language_server_id: String,
|
||||||
|
worktree: &Worktree,
|
||||||
|
) -> Result<Option<String>, String> {
|
||||||
|
let language_server_id = LanguageServerId(language_server_id);
|
||||||
|
Ok(extension()
|
||||||
|
.language_server_workspace_configuration(&language_server_id, worktree)?
|
||||||
|
.and_then(|value| serde_json::to_string(&value).ok()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn labels_for_completions(
|
fn labels_for_completions(
|
||||||
|
30
crates/extension_api/src/settings.rs
Normal file
30
crates/extension_api/src/settings.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#[path = "../wit/since_v0.0.6/settings.rs"]
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
use crate::{wit, Result, SettingsLocation, Worktree};
|
||||||
|
use serde_json;
|
||||||
|
pub use types::*;
|
||||||
|
|
||||||
|
impl LanguageSettings {
|
||||||
|
pub fn for_worktree(language: Option<&str>, worktree: &Worktree) -> Result<Self> {
|
||||||
|
let location = SettingsLocation {
|
||||||
|
worktree_id: worktree.id(),
|
||||||
|
path: worktree.root_path(),
|
||||||
|
};
|
||||||
|
let settings_json = wit::get_settings(Some(&location), "language", language)?;
|
||||||
|
let settings: Self = serde_json::from_str(&settings_json).map_err(|err| err.to_string())?;
|
||||||
|
Ok(settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LspSettings {
|
||||||
|
pub fn for_worktree(language_server_name: &str, worktree: &Worktree) -> Result<Self> {
|
||||||
|
let location = SettingsLocation {
|
||||||
|
worktree_id: worktree.id(),
|
||||||
|
path: worktree.root_path(),
|
||||||
|
};
|
||||||
|
let settings_json = wit::get_settings(Some(&location), "lsp", Some(language_server_name))?;
|
||||||
|
let settings: Self = serde_json::from_str(&settings_json).map_err(|err| err.to_string())?;
|
||||||
|
Ok(settings)
|
||||||
|
}
|
||||||
|
}
|
@ -79,6 +79,13 @@ world extension {
|
|||||||
/// Returns operating system and architecture for the current platform.
|
/// Returns operating system and architecture for the current platform.
|
||||||
import current-platform: func() -> tuple<os, architecture>;
|
import current-platform: func() -> tuple<os, architecture>;
|
||||||
|
|
||||||
|
record settings-location {
|
||||||
|
worktree-id: u64,
|
||||||
|
path: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
import get-settings: func(path: option<settings-location>, category: string, key: option<string>) -> result<string, string>;
|
||||||
|
|
||||||
/// Returns the path to the Node binary used by Zed.
|
/// Returns the path to the Node binary used by Zed.
|
||||||
import node-binary-path: func() -> result<string, string>;
|
import node-binary-path: func() -> result<string, string>;
|
||||||
|
|
||||||
@ -121,6 +128,10 @@ world extension {
|
|||||||
|
|
||||||
/// A Zed worktree.
|
/// A Zed worktree.
|
||||||
resource 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.
|
/// Returns the textual contents of the specified file in the worktree.
|
||||||
read-text-file: func(path: string) -> result<string, string>;
|
read-text-file: func(path: string) -> result<string, string>;
|
||||||
/// Returns the path to the given binary name, if one is present on the `$PATH`.
|
/// Returns the path to the given binary name, if one is present on the `$PATH`.
|
||||||
@ -137,6 +148,9 @@ world extension {
|
|||||||
/// The initialization options are represented as a JSON string.
|
/// 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>;
|
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>;
|
||||||
|
|
||||||
record code-label {
|
record code-label {
|
||||||
/// The source code to parse with Tree-sitter.
|
/// The source code to parse with Tree-sitter.
|
||||||
code: string,
|
code: string,
|
||||||
|
20
crates/extension_api/wit/since_v0.0.6/settings.rs
Normal file
20
crates/extension_api/wit/since_v0.0.6/settings.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct LanguageSettings {
|
||||||
|
pub tab_size: NonZeroU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct LspSettings {
|
||||||
|
pub binary: Option<BinarySettings>,
|
||||||
|
pub initialization_options: Option<serde_json::Value>,
|
||||||
|
pub settings: Option<serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct BinarySettings {
|
||||||
|
pub path: Option<String>,
|
||||||
|
pub arguments: Option<Vec<String>>,
|
||||||
|
}
|
@ -22,6 +22,7 @@ fn suggested_extensions() -> &'static HashMap<&'static str, Arc<str>> {
|
|||||||
("clojure", "cljs"),
|
("clojure", "cljs"),
|
||||||
("clojure", "edn"),
|
("clojure", "edn"),
|
||||||
("csharp", "cs"),
|
("csharp", "cs"),
|
||||||
|
("dart", "dart"),
|
||||||
("dockerfile", "Dockerfile"),
|
("dockerfile", "Dockerfile"),
|
||||||
("elisp", "el"),
|
("elisp", "el"),
|
||||||
("erlang", "erl"),
|
("erlang", "erl"),
|
||||||
|
@ -197,10 +197,6 @@ impl CachedLspAdapter {
|
|||||||
self.adapter.code_action_kinds()
|
self.adapter.code_action_kinds()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn workspace_configuration(&self, workspace_root: &Path, cx: &mut AppContext) -> Value {
|
|
||||||
self.adapter.workspace_configuration(workspace_root, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
|
pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
|
||||||
self.adapter.process_diagnostics(params)
|
self.adapter.process_diagnostics(params)
|
||||||
}
|
}
|
||||||
@ -243,6 +239,8 @@ impl CachedLspAdapter {
|
|||||||
pub trait LspAdapterDelegate: Send + Sync {
|
pub trait LspAdapterDelegate: Send + Sync {
|
||||||
fn show_notification(&self, message: &str, cx: &mut AppContext);
|
fn show_notification(&self, message: &str, cx: &mut AppContext);
|
||||||
fn http_client(&self) -> Arc<dyn HttpClient>;
|
fn http_client(&self) -> Arc<dyn HttpClient>;
|
||||||
|
fn worktree_id(&self) -> u64;
|
||||||
|
fn worktree_root_path(&self) -> &Path;
|
||||||
fn update_status(&self, language: LanguageServerName, status: LanguageServerBinaryStatus);
|
fn update_status(&self, language: LanguageServerName, status: LanguageServerBinaryStatus);
|
||||||
|
|
||||||
async fn which(&self, command: &OsStr) -> Option<PathBuf>;
|
async fn which(&self, command: &OsStr) -> Option<PathBuf>;
|
||||||
@ -445,8 +443,12 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_configuration(&self, _workspace_root: &Path, _cx: &mut AppContext) -> Value {
|
async fn workspace_configuration(
|
||||||
serde_json::json!({})
|
self: Arc<Self>,
|
||||||
|
_: &Arc<dyn LspAdapterDelegate>,
|
||||||
|
_cx: &mut AsyncAppContext,
|
||||||
|
) -> Result<Value> {
|
||||||
|
Ok(serde_json::json!({}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of code actions supported by a given LspAdapter
|
/// Returns a list of code actions supported by a given LspAdapter
|
||||||
|
@ -40,7 +40,6 @@ tree-sitter-bash.workspace = true
|
|||||||
tree-sitter-c.workspace = true
|
tree-sitter-c.workspace = true
|
||||||
tree-sitter-cpp.workspace = true
|
tree-sitter-cpp.workspace = true
|
||||||
tree-sitter-css.workspace = true
|
tree-sitter-css.workspace = true
|
||||||
tree-sitter-dart.workspace = true
|
|
||||||
tree-sitter-elixir.workspace = true
|
tree-sitter-elixir.workspace = true
|
||||||
tree-sitter-elm.workspace = true
|
tree-sitter-elm.workspace = true
|
||||||
tree-sitter-embedded-template.workspace = true
|
tree-sitter-embedded-template.workspace = true
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
use anyhow::{anyhow, Result};
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use gpui::AppContext;
|
|
||||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
|
||||||
use lsp::LanguageServerBinary;
|
|
||||||
use project::project_settings::ProjectSettings;
|
|
||||||
use serde_json::Value;
|
|
||||||
use settings::Settings;
|
|
||||||
use std::{
|
|
||||||
any::Any,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct DartLanguageServer;
|
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
|
||||||
impl LspAdapter for DartLanguageServer {
|
|
||||||
fn name(&self) -> LanguageServerName {
|
|
||||||
LanguageServerName("dart".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn fetch_latest_server_version(
|
|
||||||
&self,
|
|
||||||
_: &dyn LspAdapterDelegate,
|
|
||||||
) -> Result<Box<dyn 'static + Send + Any>> {
|
|
||||||
Ok(Box::new(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn fetch_server_binary(
|
|
||||||
&self,
|
|
||||||
_: Box<dyn 'static + Send + Any>,
|
|
||||||
_: PathBuf,
|
|
||||||
_: &dyn LspAdapterDelegate,
|
|
||||||
) -> Result<LanguageServerBinary> {
|
|
||||||
Err(anyhow!("dart must me installed from dart.dev/get-dart"))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn cached_server_binary(
|
|
||||||
&self,
|
|
||||||
_: PathBuf,
|
|
||||||
_: &dyn LspAdapterDelegate,
|
|
||||||
) -> Option<LanguageServerBinary> {
|
|
||||||
Some(LanguageServerBinary {
|
|
||||||
path: "dart".into(),
|
|
||||||
env: None,
|
|
||||||
arguments: vec!["language-server".into(), "--protocol=lsp".into()],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_be_reinstalled(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn workspace_configuration(&self, _workspace_root: &Path, cx: &mut AppContext) -> Value {
|
|
||||||
let settings = ProjectSettings::get_global(cx)
|
|
||||||
.lsp
|
|
||||||
.get("dart")
|
|
||||||
.and_then(|s| s.settings.clone())
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
serde_json::json!({
|
|
||||||
"dart": settings
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::{AppContext, AsyncAppContext, Task};
|
use gpui::{AsyncAppContext, Task};
|
||||||
pub use language::*;
|
pub use language::*;
|
||||||
use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind};
|
use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind};
|
||||||
use project::project_settings::ProjectSettings;
|
use project::project_settings::ProjectSettings;
|
||||||
@ -14,7 +14,7 @@ use std::{
|
|||||||
any::Any,
|
any::Any,
|
||||||
env::consts,
|
env::consts,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
path::{Path, PathBuf},
|
path::PathBuf,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering::SeqCst},
|
atomic::{AtomicBool, Ordering::SeqCst},
|
||||||
Arc,
|
Arc,
|
||||||
@ -278,16 +278,22 @@ impl LspAdapter for ElixirLspAdapter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_configuration(&self, _workspace_root: &Path, cx: &mut AppContext) -> Value {
|
async fn workspace_configuration(
|
||||||
let settings = ProjectSettings::get_global(cx)
|
self: Arc<Self>,
|
||||||
.lsp
|
_: &Arc<dyn LspAdapterDelegate>,
|
||||||
.get("elixir-ls")
|
cx: &mut AsyncAppContext,
|
||||||
.and_then(|s| s.settings.clone())
|
) -> Result<Value> {
|
||||||
.unwrap_or_default();
|
let settings = cx.update(|cx| {
|
||||||
|
ProjectSettings::get_global(cx)
|
||||||
|
.lsp
|
||||||
|
.get("elixir-ls")
|
||||||
|
.and_then(|s| s.settings.clone())
|
||||||
|
.unwrap_or_default()
|
||||||
|
})?;
|
||||||
|
|
||||||
serde_json::json!({
|
Ok(serde_json::json!({
|
||||||
"elixirLS": settings
|
"elixirLS": settings
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::AppContext;
|
use gpui::AsyncAppContext;
|
||||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
use lsp::LanguageServerBinary;
|
use lsp::LanguageServerBinary;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
@ -94,16 +94,22 @@ impl LspAdapter for ElmLspAdapter {
|
|||||||
get_cached_server_binary(container_dir, &*self.node).await
|
get_cached_server_binary(container_dir, &*self.node).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_configuration(&self, _workspace_root: &Path, cx: &mut AppContext) -> Value {
|
async fn workspace_configuration(
|
||||||
|
self: Arc<Self>,
|
||||||
|
_: &Arc<dyn LspAdapterDelegate>,
|
||||||
|
cx: &mut AsyncAppContext,
|
||||||
|
) -> Result<Value> {
|
||||||
// elm-language-server expects workspace didChangeConfiguration notification
|
// elm-language-server expects workspace didChangeConfiguration notification
|
||||||
// params to be the same as lsp initialization_options
|
// params to be the same as lsp initialization_options
|
||||||
let override_options = ProjectSettings::get_global(cx)
|
let override_options = cx.update(|cx| {
|
||||||
.lsp
|
ProjectSettings::get_global(cx)
|
||||||
.get(SERVER_NAME)
|
.lsp
|
||||||
.and_then(|s| s.initialization_options.clone())
|
.get(SERVER_NAME)
|
||||||
.unwrap_or_default();
|
.and_then(|s| s.initialization_options.clone())
|
||||||
|
.unwrap_or_default()
|
||||||
|
})?;
|
||||||
|
|
||||||
match override_options.clone().as_object_mut() {
|
Ok(match override_options.clone().as_object_mut() {
|
||||||
Some(op) => {
|
Some(op) => {
|
||||||
// elm-language-server requests workspace configuration
|
// elm-language-server requests workspace configuration
|
||||||
// for the `elmLS` section, so we have to nest
|
// for the `elmLS` section, so we have to nest
|
||||||
@ -112,7 +118,7 @@ impl LspAdapter for ElmLspAdapter {
|
|||||||
serde_json::to_value(op).unwrap_or_default()
|
serde_json::to_value(op).unwrap_or_default()
|
||||||
}
|
}
|
||||||
None => override_options,
|
None => override_options,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use async_trait::async_trait;
|
|||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use feature_flags::FeatureFlagAppExt;
|
use feature_flags::FeatureFlagAppExt;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::AppContext;
|
use gpui::{AppContext, AsyncAppContext};
|
||||||
use language::{LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
use lsp::LanguageServerBinary;
|
use lsp::LanguageServerBinary;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
@ -152,10 +152,16 @@ impl LspAdapter for JsonLspAdapter {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_configuration(&self, _workspace_root: &Path, cx: &mut AppContext) -> Value {
|
async fn workspace_configuration(
|
||||||
self.workspace_config
|
self: Arc<Self>,
|
||||||
.get_or_init(|| Self::get_workspace_config(self.languages.language_names(), cx))
|
_: &Arc<dyn LspAdapterDelegate>,
|
||||||
.clone()
|
cx: &mut AsyncAppContext,
|
||||||
|
) -> Result<Value> {
|
||||||
|
cx.update(|cx| {
|
||||||
|
self.workspace_config
|
||||||
|
.get_or_init(|| Self::get_workspace_config(self.languages.language_names(), cx))
|
||||||
|
.clone()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn language_ids(&self) -> HashMap<String, String> {
|
fn language_ids(&self) -> HashMap<String, String> {
|
||||||
|
@ -13,7 +13,6 @@ use self::{deno::DenoSettings, elixir::ElixirSettings};
|
|||||||
|
|
||||||
mod c;
|
mod c;
|
||||||
mod css;
|
mod css;
|
||||||
mod dart;
|
|
||||||
mod deno;
|
mod deno;
|
||||||
mod elixir;
|
mod elixir;
|
||||||
mod elm;
|
mod elm;
|
||||||
@ -92,7 +91,6 @@ pub fn init(
|
|||||||
("typescript", tree_sitter_typescript::language_typescript()),
|
("typescript", tree_sitter_typescript::language_typescript()),
|
||||||
("vue", tree_sitter_vue::language()),
|
("vue", tree_sitter_vue::language()),
|
||||||
("yaml", tree_sitter_yaml::language()),
|
("yaml", tree_sitter_yaml::language()),
|
||||||
("dart", tree_sitter_dart::language()),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
macro_rules! language {
|
macro_rules! language {
|
||||||
@ -312,7 +310,6 @@ pub fn init(
|
|||||||
vec![Arc::new(terraform::TerraformLspAdapter)]
|
vec![Arc::new(terraform::TerraformLspAdapter)]
|
||||||
);
|
);
|
||||||
language!("hcl", vec![]);
|
language!("hcl", vec![]);
|
||||||
language!("dart", vec![Arc::new(dart::DartLanguageServer {})]);
|
|
||||||
|
|
||||||
languages.register_secondary_lsp_adapter(
|
languages.register_secondary_lsp_adapter(
|
||||||
"Astro".into(),
|
"Astro".into(),
|
||||||
|
@ -2,7 +2,7 @@ use anyhow::{anyhow, Result};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::AppContext;
|
use gpui::AsyncAppContext;
|
||||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
use lsp::LanguageServerBinary;
|
use lsp::LanguageServerBinary;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
@ -107,12 +107,16 @@ impl LspAdapter for TailwindLspAdapter {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_configuration(&self, _workspace_root: &Path, _: &mut AppContext) -> Value {
|
async fn workspace_configuration(
|
||||||
json!({
|
self: Arc<Self>,
|
||||||
|
_: &Arc<dyn LspAdapterDelegate>,
|
||||||
|
_cx: &mut AsyncAppContext,
|
||||||
|
) -> Result<Value> {
|
||||||
|
Ok(json!({
|
||||||
"tailwindCSS": {
|
"tailwindCSS": {
|
||||||
"emmetCompletions": true,
|
"emmetCompletions": true,
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn language_ids(&self) -> HashMap<String, String> {
|
fn language_ids(&self) -> HashMap<String, String> {
|
||||||
|
@ -3,7 +3,7 @@ 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 collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::AppContext;
|
use gpui::AsyncAppContext;
|
||||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
use lsp::{CodeActionKind, LanguageServerBinary};
|
use lsp::{CodeActionKind, LanguageServerBinary};
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
@ -245,12 +245,20 @@ impl EsLintLspAdapter {
|
|||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl LspAdapter for EsLintLspAdapter {
|
impl LspAdapter for EsLintLspAdapter {
|
||||||
fn workspace_configuration(&self, workspace_root: &Path, cx: &mut AppContext) -> Value {
|
async fn workspace_configuration(
|
||||||
let eslint_user_settings = ProjectSettings::get_global(cx)
|
self: Arc<Self>,
|
||||||
.lsp
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
.get(Self::SERVER_NAME)
|
cx: &mut AsyncAppContext,
|
||||||
.and_then(|s| s.settings.clone())
|
) -> Result<Value> {
|
||||||
.unwrap_or_default();
|
let workspace_root = delegate.worktree_root_path();
|
||||||
|
|
||||||
|
let eslint_user_settings = cx.update(|cx| {
|
||||||
|
ProjectSettings::get_global(cx)
|
||||||
|
.lsp
|
||||||
|
.get(Self::SERVER_NAME)
|
||||||
|
.and_then(|s| s.settings.clone())
|
||||||
|
.unwrap_or_default()
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut code_action_on_save = json!({
|
let mut code_action_on_save = json!({
|
||||||
// We enable this, but without also configuring `code_actions_on_format`
|
// We enable this, but without also configuring `code_actions_on_format`
|
||||||
@ -283,7 +291,7 @@ impl LspAdapter for EsLintLspAdapter {
|
|||||||
.iter()
|
.iter()
|
||||||
.any(|file| workspace_root.join(file).is_file());
|
.any(|file| workspace_root.join(file).is_file());
|
||||||
|
|
||||||
json!({
|
Ok(json!({
|
||||||
"": {
|
"": {
|
||||||
"validate": "on",
|
"validate": "on",
|
||||||
"rulesCustomizations": [],
|
"rulesCustomizations": [],
|
||||||
@ -301,7 +309,7 @@ impl LspAdapter for EsLintLspAdapter {
|
|||||||
"useFlatConfig": use_flat_config,
|
"useFlatConfig": use_flat_config,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(&self) -> LanguageServerName {
|
fn name(&self) -> LanguageServerName {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::AppContext;
|
use gpui::AsyncAppContext;
|
||||||
use language::{
|
use language::{
|
||||||
language_settings::all_language_settings, LanguageServerName, LspAdapter, LspAdapterDelegate,
|
language_settings::all_language_settings, LanguageServerName, LspAdapter, LspAdapterDelegate,
|
||||||
};
|
};
|
||||||
@ -92,17 +92,26 @@ impl LspAdapter for YamlLspAdapter {
|
|||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
get_cached_server_binary(container_dir, &*self.node).await
|
get_cached_server_binary(container_dir, &*self.node).await
|
||||||
}
|
}
|
||||||
fn workspace_configuration(&self, _workspace_root: &Path, cx: &mut AppContext) -> Value {
|
|
||||||
serde_json::json!({
|
async fn workspace_configuration(
|
||||||
|
self: Arc<Self>,
|
||||||
|
_: &Arc<dyn LspAdapterDelegate>,
|
||||||
|
cx: &mut AsyncAppContext,
|
||||||
|
) -> Result<Value> {
|
||||||
|
let tab_size = cx.update(|cx| {
|
||||||
|
all_language_settings(None, cx)
|
||||||
|
.language(Some("YAML"))
|
||||||
|
.tab_size
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(serde_json::json!({
|
||||||
"yaml": {
|
"yaml": {
|
||||||
"keyOrdering": false
|
"keyOrdering": false
|
||||||
},
|
},
|
||||||
"[yaml]": {
|
"[yaml]": {
|
||||||
"editor.tabSize": all_language_settings(None, cx)
|
"editor.tabSize": tab_size
|
||||||
.language(Some("YAML"))
|
|
||||||
.tab_size,
|
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2857,21 +2857,29 @@ impl Project {
|
|||||||
|
|
||||||
cx.spawn(move |this, mut cx| async move {
|
cx.spawn(move |this, mut cx| async move {
|
||||||
while let Some(()) = settings_changed_rx.next().await {
|
while let Some(()) = settings_changed_rx.next().await {
|
||||||
let servers: Vec<_> = this.update(&mut cx, |this, _| {
|
let servers = this.update(&mut cx, |this, cx| {
|
||||||
this.language_servers
|
this.language_server_ids
|
||||||
.values()
|
.iter()
|
||||||
.filter_map(|state| match state {
|
.filter_map(|((worktree_id, _), server_id)| {
|
||||||
LanguageServerState::Starting(_) => None,
|
let worktree = this.worktree_for_id(*worktree_id, cx)?;
|
||||||
LanguageServerState::Running {
|
let state = this.language_servers.get(server_id)?;
|
||||||
adapter, server, ..
|
let delegate = ProjectLspAdapterDelegate::new(this, &worktree, cx);
|
||||||
} => Some((adapter.clone(), server.clone())),
|
match state {
|
||||||
|
LanguageServerState::Starting(_) => None,
|
||||||
|
LanguageServerState::Running {
|
||||||
|
adapter, server, ..
|
||||||
|
} => Some((
|
||||||
|
adapter.adapter.clone(),
|
||||||
|
server.clone(),
|
||||||
|
delegate as Arc<dyn LspAdapterDelegate>,
|
||||||
|
)),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect::<Vec<_>>()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
for (adapter, server) in servers {
|
for (adapter, server, delegate) in servers {
|
||||||
let settings =
|
let settings = adapter.workspace_configuration(&delegate, &mut cx).await?;
|
||||||
cx.update(|cx| adapter.workspace_configuration(server.root_path(), cx))?;
|
|
||||||
|
|
||||||
server
|
server
|
||||||
.notify::<lsp::notification::DidChangeConfiguration>(
|
.notify::<lsp::notification::DidChangeConfiguration>(
|
||||||
@ -2985,12 +2993,13 @@ impl Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
|
let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
|
||||||
|
let lsp_adapter_delegate = ProjectLspAdapterDelegate::new(self, worktree_handle, cx);
|
||||||
let pending_server = match self.languages.create_pending_language_server(
|
let pending_server = match self.languages.create_pending_language_server(
|
||||||
stderr_capture.clone(),
|
stderr_capture.clone(),
|
||||||
language.clone(),
|
language.clone(),
|
||||||
adapter.clone(),
|
adapter.clone(),
|
||||||
Arc::clone(&worktree_path),
|
Arc::clone(&worktree_path),
|
||||||
ProjectLspAdapterDelegate::new(self, worktree_handle, cx),
|
lsp_adapter_delegate.clone(),
|
||||||
cx,
|
cx,
|
||||||
) {
|
) {
|
||||||
Some(pending_server) => pending_server,
|
Some(pending_server) => pending_server,
|
||||||
@ -3018,7 +3027,7 @@ impl Project {
|
|||||||
cx.spawn(move |this, mut cx| async move {
|
cx.spawn(move |this, mut cx| async move {
|
||||||
let result = Self::setup_and_insert_language_server(
|
let result = Self::setup_and_insert_language_server(
|
||||||
this.clone(),
|
this.clone(),
|
||||||
&worktree_path,
|
lsp_adapter_delegate,
|
||||||
override_options,
|
override_options,
|
||||||
pending_server,
|
pending_server,
|
||||||
adapter.clone(),
|
adapter.clone(),
|
||||||
@ -3142,7 +3151,7 @@ impl Project {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn setup_and_insert_language_server(
|
async fn setup_and_insert_language_server(
|
||||||
this: WeakModel<Self>,
|
this: WeakModel<Self>,
|
||||||
worktree_path: &Path,
|
delegate: Arc<dyn LspAdapterDelegate>,
|
||||||
override_initialization_options: Option<serde_json::Value>,
|
override_initialization_options: Option<serde_json::Value>,
|
||||||
pending_server: PendingLanguageServer,
|
pending_server: PendingLanguageServer,
|
||||||
adapter: Arc<CachedLspAdapter>,
|
adapter: Arc<CachedLspAdapter>,
|
||||||
@ -3155,7 +3164,7 @@ impl Project {
|
|||||||
this.clone(),
|
this.clone(),
|
||||||
override_initialization_options,
|
override_initialization_options,
|
||||||
pending_server,
|
pending_server,
|
||||||
worktree_path,
|
delegate,
|
||||||
adapter.clone(),
|
adapter.clone(),
|
||||||
server_id,
|
server_id,
|
||||||
cx,
|
cx,
|
||||||
@ -3185,13 +3194,16 @@ impl Project {
|
|||||||
this: WeakModel<Self>,
|
this: WeakModel<Self>,
|
||||||
override_options: Option<serde_json::Value>,
|
override_options: Option<serde_json::Value>,
|
||||||
pending_server: PendingLanguageServer,
|
pending_server: PendingLanguageServer,
|
||||||
worktree_path: &Path,
|
delegate: Arc<dyn LspAdapterDelegate>,
|
||||||
adapter: Arc<CachedLspAdapter>,
|
adapter: Arc<CachedLspAdapter>,
|
||||||
server_id: LanguageServerId,
|
server_id: LanguageServerId,
|
||||||
cx: &mut AsyncAppContext,
|
cx: &mut AsyncAppContext,
|
||||||
) -> Result<Arc<LanguageServer>> {
|
) -> Result<Arc<LanguageServer>> {
|
||||||
let workspace_config =
|
let workspace_config = adapter
|
||||||
cx.update(|cx| adapter.workspace_configuration(worktree_path, cx))?;
|
.adapter
|
||||||
|
.clone()
|
||||||
|
.workspace_configuration(&delegate, cx)
|
||||||
|
.await?;
|
||||||
let (language_server, mut initialization_options) = pending_server.task.await?;
|
let (language_server, mut initialization_options) = pending_server.task.await?;
|
||||||
|
|
||||||
let name = language_server.name();
|
let name = language_server.name();
|
||||||
@ -3220,14 +3232,14 @@ impl Project {
|
|||||||
|
|
||||||
language_server
|
language_server
|
||||||
.on_request::<lsp::request::WorkspaceConfiguration, _, _>({
|
.on_request::<lsp::request::WorkspaceConfiguration, _, _>({
|
||||||
let adapter = adapter.clone();
|
let adapter = adapter.adapter.clone();
|
||||||
let worktree_path = worktree_path.to_path_buf();
|
let delegate = delegate.clone();
|
||||||
move |params, cx| {
|
move |params, mut cx| {
|
||||||
let adapter = adapter.clone();
|
let adapter = adapter.clone();
|
||||||
let worktree_path = worktree_path.clone();
|
let delegate = delegate.clone();
|
||||||
async move {
|
async move {
|
||||||
let workspace_config =
|
let workspace_config =
|
||||||
cx.update(|cx| adapter.workspace_configuration(&worktree_path, cx))?;
|
adapter.workspace_configuration(&delegate, &mut cx).await?;
|
||||||
Ok(params
|
Ok(params
|
||||||
.items
|
.items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -10315,6 +10327,14 @@ impl LspAdapterDelegate for ProjectLspAdapterDelegate {
|
|||||||
self.http_client.clone()
|
self.http_client.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn worktree_id(&self) -> u64 {
|
||||||
|
self.worktree.id().to_proto()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn worktree_root_path(&self) -> &Path {
|
||||||
|
self.worktree.abs_path().as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
async fn shell_env(&self) -> HashMap<String, String> {
|
async fn shell_env(&self) -> HashMap<String, String> {
|
||||||
self.load_shell_env().await;
|
self.load_shell_env().await;
|
||||||
self.shell_env.lock().as_ref().cloned().unwrap_or_default()
|
self.shell_env.lock().as_ref().cloned().unwrap_or_default()
|
||||||
|
@ -47,7 +47,7 @@ pub struct BinarySettings {
|
|||||||
pub arguments: Option<Vec<String>>,
|
pub arguments: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct LspSettings {
|
pub struct LspSettings {
|
||||||
pub binary: Option<BinarySettings>,
|
pub binary: Option<BinarySettings>,
|
||||||
|
16
extensions/dart/Cargo.toml
Normal file
16
extensions/dart/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "zed_dart"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
license = "Apache-2.0"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/dart.rs"
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
zed_extension_api = { path = "../../crates/extension_api" }
|
1
extensions/dart/LICENSE-APACHE
Symbolic link
1
extensions/dart/LICENSE-APACHE
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../LICENSE-APACHE
|
15
extensions/dart/extension.toml
Normal file
15
extensions/dart/extension.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
id = "dart"
|
||||||
|
name = "Dart"
|
||||||
|
description = "Dart support."
|
||||||
|
version = "0.0.1"
|
||||||
|
schema_version = 1
|
||||||
|
authors = ["Abdullah Alsigar <abdullah.alsigar@gmail.com>", "Flo <flo80@users.noreply.github.com>"]
|
||||||
|
repository = "https://github.com/zed-industries/zed"
|
||||||
|
|
||||||
|
[language_servers.dart]
|
||||||
|
name = "Dart LSP"
|
||||||
|
language = "Dart"
|
||||||
|
|
||||||
|
[grammars.dart]
|
||||||
|
repository = "https://github.com/agent3bood/tree-sitter-dart"
|
||||||
|
commit = "48934e3bf757a9b78f17bdfaa3e2b4284656fdc7"
|
123
extensions/dart/src/dart.rs
Normal file
123
extensions/dart/src/dart.rs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
use zed::lsp::CompletionKind;
|
||||||
|
use zed::settings::LspSettings;
|
||||||
|
use zed::{CodeLabel, CodeLabelSpan};
|
||||||
|
use zed_extension_api::{self as zed, serde_json, Result};
|
||||||
|
|
||||||
|
struct DartExtension;
|
||||||
|
|
||||||
|
impl zed::Extension for DartExtension {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn language_server_command(
|
||||||
|
&mut self,
|
||||||
|
_language_server_id: &zed::LanguageServerId,
|
||||||
|
worktree: &zed::Worktree,
|
||||||
|
) -> Result<zed::Command> {
|
||||||
|
let path = worktree
|
||||||
|
.which("dart")
|
||||||
|
.ok_or_else(|| "dart must be installed from dart.dev/get-dart".to_string())?;
|
||||||
|
|
||||||
|
Ok(zed::Command {
|
||||||
|
command: path,
|
||||||
|
args: vec!["language-server".to_string(), "--protocol=lsp".to_string()],
|
||||||
|
env: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn language_server_workspace_configuration(
|
||||||
|
&mut self,
|
||||||
|
_language_server_id: &zed::LanguageServerId,
|
||||||
|
worktree: &zed::Worktree,
|
||||||
|
) -> Result<Option<serde_json::Value>> {
|
||||||
|
let settings = LspSettings::for_worktree("dart", worktree)
|
||||||
|
.ok()
|
||||||
|
.and_then(|lsp_settings| lsp_settings.settings.clone())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(Some(serde_json::json!({
|
||||||
|
"dart": settings
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn label_for_completion(
|
||||||
|
&self,
|
||||||
|
_language_server_id: &zed::LanguageServerId,
|
||||||
|
completion: zed::lsp::Completion,
|
||||||
|
) -> Option<CodeLabel> {
|
||||||
|
let arrow = " → ";
|
||||||
|
|
||||||
|
match completion.kind? {
|
||||||
|
CompletionKind::Class => Some(CodeLabel {
|
||||||
|
filter_range: (0..completion.label.len()).into(),
|
||||||
|
spans: vec![CodeLabelSpan::literal(
|
||||||
|
completion.label,
|
||||||
|
Some("type".into()),
|
||||||
|
)],
|
||||||
|
code: String::new(),
|
||||||
|
}),
|
||||||
|
CompletionKind::Function | CompletionKind::Constructor | CompletionKind::Method => {
|
||||||
|
let mut parts = completion.detail.as_ref()?.split(arrow);
|
||||||
|
let (name, _) = completion.label.split_once('(')?;
|
||||||
|
let parameter_list = parts.next()?;
|
||||||
|
let return_type = parts.next()?;
|
||||||
|
let fn_name = " a";
|
||||||
|
let fat_arrow = " => ";
|
||||||
|
let call_expr = "();";
|
||||||
|
|
||||||
|
let code =
|
||||||
|
format!("{return_type}{fn_name}{parameter_list}{fat_arrow}{name}{call_expr}");
|
||||||
|
|
||||||
|
let parameter_list_start = return_type.len() + fn_name.len();
|
||||||
|
|
||||||
|
Some(CodeLabel {
|
||||||
|
spans: vec![
|
||||||
|
CodeLabelSpan::code_range(
|
||||||
|
code.len() - call_expr.len() - name.len()..code.len() - call_expr.len(),
|
||||||
|
),
|
||||||
|
CodeLabelSpan::code_range(
|
||||||
|
parameter_list_start..parameter_list_start + parameter_list.len(),
|
||||||
|
),
|
||||||
|
CodeLabelSpan::literal(arrow, None),
|
||||||
|
CodeLabelSpan::code_range(0..return_type.len()),
|
||||||
|
],
|
||||||
|
filter_range: (0..name.len()).into(),
|
||||||
|
code,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
CompletionKind::Property => {
|
||||||
|
let class_start = "class A {";
|
||||||
|
let get = " get ";
|
||||||
|
let property_end = " => a; }";
|
||||||
|
let ty = completion.detail?;
|
||||||
|
let name = completion.label;
|
||||||
|
|
||||||
|
let code = format!("{class_start}{ty}{get}{name}{property_end}");
|
||||||
|
let name_start = class_start.len() + ty.len() + get.len();
|
||||||
|
|
||||||
|
Some(CodeLabel {
|
||||||
|
spans: vec![
|
||||||
|
CodeLabelSpan::code_range(name_start..name_start + name.len()),
|
||||||
|
CodeLabelSpan::literal(arrow, None),
|
||||||
|
CodeLabelSpan::code_range(class_start.len()..class_start.len() + ty.len()),
|
||||||
|
],
|
||||||
|
filter_range: (0..name.len()).into(),
|
||||||
|
code,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
CompletionKind::Variable => {
|
||||||
|
let name = completion.label;
|
||||||
|
|
||||||
|
Some(CodeLabel {
|
||||||
|
filter_range: (0..name.len()).into(),
|
||||||
|
spans: vec![CodeLabelSpan::literal(name, Some("variable".into()))],
|
||||||
|
code: String::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zed::register_extension!(DartExtension);
|
@ -13,4 +13,5 @@ path = "src/svelte.rs"
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
zed_extension_api = "0.0.4"
|
zed_extension_api = { path = "../../crates/extension_api" }
|
||||||
|
# zed_extension_api = "0.0.4"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
use zed_extension_api::{self as zed, Result};
|
use zed_extension_api::{self as zed, serde_json, Result};
|
||||||
|
|
||||||
struct SvelteExtension {
|
struct SvelteExtension {
|
||||||
did_find_server: bool,
|
did_find_server: bool,
|
||||||
@ -13,14 +13,14 @@ impl SvelteExtension {
|
|||||||
fs::metadata(SERVER_PATH).map_or(false, |stat| stat.is_file())
|
fs::metadata(SERVER_PATH).map_or(false, |stat| stat.is_file())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn server_script_path(&mut self, config: zed::LanguageServerConfig) -> Result<String> {
|
fn server_script_path(&mut self, id: &zed::LanguageServerId) -> Result<String> {
|
||||||
let server_exists = self.server_exists();
|
let server_exists = self.server_exists();
|
||||||
if self.did_find_server && server_exists {
|
if self.did_find_server && server_exists {
|
||||||
return Ok(SERVER_PATH.to_string());
|
return Ok(SERVER_PATH.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
zed::set_language_server_installation_status(
|
zed::set_language_server_installation_status(
|
||||||
&config.name,
|
id,
|
||||||
&zed::LanguageServerInstallationStatus::CheckingForUpdate,
|
&zed::LanguageServerInstallationStatus::CheckingForUpdate,
|
||||||
);
|
);
|
||||||
let version = zed::npm_package_latest_version(PACKAGE_NAME)?;
|
let version = zed::npm_package_latest_version(PACKAGE_NAME)?;
|
||||||
@ -29,7 +29,7 @@ impl SvelteExtension {
|
|||||||
|| zed::npm_package_installed_version(PACKAGE_NAME)?.as_ref() != Some(&version)
|
|| zed::npm_package_installed_version(PACKAGE_NAME)?.as_ref() != Some(&version)
|
||||||
{
|
{
|
||||||
zed::set_language_server_installation_status(
|
zed::set_language_server_installation_status(
|
||||||
&config.name,
|
id,
|
||||||
&zed::LanguageServerInstallationStatus::Downloading,
|
&zed::LanguageServerInstallationStatus::Downloading,
|
||||||
);
|
);
|
||||||
let result = zed::npm_install_package(PACKAGE_NAME, &version);
|
let result = zed::npm_install_package(PACKAGE_NAME, &version);
|
||||||
@ -63,10 +63,10 @@ impl zed::Extension for SvelteExtension {
|
|||||||
|
|
||||||
fn language_server_command(
|
fn language_server_command(
|
||||||
&mut self,
|
&mut self,
|
||||||
config: zed::LanguageServerConfig,
|
id: &zed::LanguageServerId,
|
||||||
_: &zed::Worktree,
|
_: &zed::Worktree,
|
||||||
) -> Result<zed::Command> {
|
) -> Result<zed::Command> {
|
||||||
let server_path = self.server_script_path(config)?;
|
let server_path = self.server_script_path(id)?;
|
||||||
Ok(zed::Command {
|
Ok(zed::Command {
|
||||||
command: zed::node_binary_path()?,
|
command: zed::node_binary_path()?,
|
||||||
args: vec![
|
args: vec![
|
||||||
@ -83,10 +83,10 @@ impl zed::Extension for SvelteExtension {
|
|||||||
|
|
||||||
fn language_server_initialization_options(
|
fn language_server_initialization_options(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: zed::LanguageServerConfig,
|
_: &zed::LanguageServerId,
|
||||||
_: &zed::Worktree,
|
_: &zed::Worktree,
|
||||||
) -> Result<Option<String>> {
|
) -> Result<Option<serde_json::Value>> {
|
||||||
let config = r#"{
|
let config = serde_json::json!({
|
||||||
"inlayHints": {
|
"inlayHints": {
|
||||||
"parameterNames": {
|
"parameterNames": {
|
||||||
"enabled": "all",
|
"enabled": "all",
|
||||||
@ -109,17 +109,15 @@ impl zed::Extension for SvelteExtension {
|
|||||||
"enabled": true
|
"enabled": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}"#;
|
});
|
||||||
|
|
||||||
Ok(Some(format!(
|
Ok(Some(serde_json::json!({
|
||||||
r#"{{
|
"provideFormatter": true,
|
||||||
"provideFormatter": true,
|
"configuration": {
|
||||||
"configuration": {{
|
"typescript": config,
|
||||||
"typescript": {config},
|
"javascript": config
|
||||||
"javascript": {config}
|
}
|
||||||
}}
|
})))
|
||||||
}}"#
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user