Detailed changes
@@ -209,7 +209,7 @@ async fn resolve_dynamic_schema(
let schema = match schema_name {
"settings" if rest.is_some_and(|r| r.starts_with("lsp/")) => {
- let lsp_name = rest
+ let lsp_path = rest
.and_then(|r| {
r.strip_prefix(
LSP_SETTINGS_SCHEMA_URL_PREFIX
@@ -220,6 +220,26 @@ async fn resolve_dynamic_schema(
})
.context("Invalid LSP schema path")?;
+ // Parse the schema type from the path:
+ // - "rust-analyzer/initialization_options" → initialization_options_schema
+ // - "rust-analyzer/settings" → settings_schema
+ enum LspSchemaKind {
+ InitializationOptions,
+ Settings,
+ }
+ let (lsp_name, schema_kind) = if let Some(adapter_name) =
+ lsp_path.strip_suffix("/initialization_options")
+ {
+ (adapter_name, LspSchemaKind::InitializationOptions)
+ } else if let Some(adapter_name) = lsp_path.strip_suffix("/settings") {
+ (adapter_name, LspSchemaKind::Settings)
+ } else {
+ anyhow::bail!(
+ "Invalid LSP schema path: expected '{{adapter}}/initialization_options' or '{{adapter}}/settings', got '{}'",
+ lsp_path
+ );
+ };
+
let adapter = languages
.all_lsp_adapters()
.into_iter()
@@ -246,15 +266,19 @@ async fn resolve_dynamic_schema(
"either LSP store is not in local mode or no worktree is available"
))?;
- adapter
- .initialization_options_schema(&delegate, cx)
- .await
- .unwrap_or_else(|| {
- serde_json::json!({
- "type": "object",
- "additionalProperties": true
- })
+ let schema = match schema_kind {
+ LspSchemaKind::InitializationOptions => {
+ adapter.initialization_options_schema(&delegate, cx).await
+ }
+ LspSchemaKind::Settings => adapter.settings_schema(&delegate, cx).await,
+ };
+
+ schema.unwrap_or_else(|| {
+ serde_json::json!({
+ "type": "object",
+ "additionalProperties": true
})
+ })
}
"settings" => {
let lsp_adapter_names = languages
@@ -354,6 +354,17 @@ impl CachedLspAdapter {
.await
}
+ pub async fn settings_schema(
+ &self,
+ delegate: &Arc<dyn LspAdapterDelegate>,
+ cx: &mut AsyncApp,
+ ) -> Option<serde_json::Value> {
+ self.adapter
+ .clone()
+ .settings_schema(delegate, self.cached_binary.clone().lock_owned().await, cx)
+ .await
+ }
+
pub fn process_prompt_response(&self, context: &PromptResponseContext, cx: &mut AsyncApp) {
self.adapter.process_prompt_response(context, cx)
}
@@ -493,6 +504,18 @@ pub trait LspAdapter: 'static + Send + Sync + DynLspInstaller {
None
}
+ /// Returns the JSON schema of the settings for the language server.
+ /// This corresponds to the `settings` field in `LspSettings`, which is used
+ /// to respond to `workspace/configuration` requests from the language server.
+ async fn settings_schema(
+ self: Arc<Self>,
+ _delegate: &Arc<dyn LspAdapterDelegate>,
+ _cached_binary: OwnedMutexGuard<Option<(bool, LanguageServerBinary)>>,
+ _cx: &mut AsyncApp,
+ ) -> Option<serde_json::Value> {
+ None
+ }
+
async fn workspace_configuration(
self: Arc<Self>,
_: &Arc<dyn LspAdapterDelegate>,
@@ -1077,7 +1077,13 @@ impl SettingsStore {
properties_object.insert(
"initialization_options".to_string(),
serde_json::json!({
- "$ref": format!("{LSP_SETTINGS_SCHEMA_URL_PREFIX}{adapter_name}")
+ "$ref": format!("{LSP_SETTINGS_SCHEMA_URL_PREFIX}{adapter_name}/initialization_options")
+ }),
+ );
+ properties_object.insert(
+ "settings".to_string(),
+ serde_json::json!({
+ "$ref": format!("{LSP_SETTINGS_SCHEMA_URL_PREFIX}{adapter_name}/settings")
}),
);
}
@@ -2397,7 +2403,23 @@ mod tests {
.as_str()
.unwrap();
- assert_eq!(init_options_ref, "zed://schemas/settings/lsp/rust-analyzer");
+ assert_eq!(
+ init_options_ref,
+ "zed://schemas/settings/lsp/rust-analyzer/initialization_options"
+ );
+
+ let settings_ref = properties
+ .get("rust-analyzer")
+ .unwrap()
+ .pointer("/properties/settings/$ref")
+ .expect("settings should have a $ref")
+ .as_str()
+ .unwrap();
+
+ assert_eq!(
+ settings_ref,
+ "zed://schemas/settings/lsp/rust-analyzer/settings"
+ );
}
#[gpui::test]
@@ -2432,7 +2454,23 @@ mod tests {
.as_str()
.unwrap();
- assert_eq!(init_options_ref, "zed://schemas/settings/lsp/rust-analyzer");
+ assert_eq!(
+ init_options_ref,
+ "zed://schemas/settings/lsp/rust-analyzer/initialization_options"
+ );
+
+ let settings_ref = properties
+ .get("rust-analyzer")
+ .unwrap()
+ .pointer("/properties/settings/$ref")
+ .expect("settings should have a $ref")
+ .as_str()
+ .unwrap();
+
+ assert_eq!(
+ settings_ref,
+ "zed://schemas/settings/lsp/rust-analyzer/settings"
+ );
}
#[gpui::test]