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:
Marshall Bowers 2024-04-05 17:04:07 -04:00 committed by GitHub
parent 4aaf3459c4
commit c851e6edba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 586 additions and 187 deletions

View file

@ -15,6 +15,8 @@ workspace = true
path = "src/extension_api.rs"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
wit-bindgen = "0.22"
[package.metadata.component]

View file

@ -1,9 +1,13 @@
//! The Zed Rust Extension API allows you write extensions for [Zed](https://zed.dev/) in Rust.
pub mod settings;
use core::fmt;
use wit::*;
pub use serde_json;
// WIT re-exports.
//
// 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,
_language_server_id: &LanguageServerId,
_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)
}
@ -142,7 +155,19 @@ impl wit::Guest for Component {
worktree: &Worktree,
) -> Result<Option<String>, String> {
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(

View 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)
}
}

View file

@ -79,6 +79,13 @@ world extension {
/// Returns operating system and architecture for the current platform.
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.
import node-binary-path: func() -> result<string, string>;
@ -121,6 +128,10 @@ world extension {
/// 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`.
@ -137,6 +148,9 @@ world extension {
/// 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>;
record code-label {
/// The source code to parse with Tree-sitter.
code: string,

View 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>>,
}