From c1907c94d2dbd0fdd4ccb8b3af6e9fa29ae1d38d Mon Sep 17 00:00:00 2001 From: Bae Seokjae <67224427+baeseokjae@users.noreply.github.com> Date: Thu, 12 Feb 2026 23:58:38 +0900 Subject: [PATCH] json_schema_store: Include available LSP adapters in settings schema (#46766) Closes #46556 ## Summary - Fix "Property `ty` is not allowed" warning in `settings.json` for LSP adapters registered via `register_available_lsp_adapter()` - Add `available_lsp_adapter_names()` method to include these adapters in schema generation - Support `initialization_options` schema lookup for available adapters ## Problem LSP adapters registered via `register_available_lsp_adapter()` were not included in the settings JSON schema. This caused validation warnings like: Property ty is not allowed Even though `ty` is a built-in Python language server that works correctly. **Affected adapters:** - `ty`, `py`, `python-lsp-server` - `eslint`, `vtsls`, `typescript-language-server` - `tailwindcss-language-server`, `tailwindcss-intellisense-css` ## Solution Schema generation now queries both: 1. `all_lsp_adapters()` - adapters bound to specific languages 2. `available_lsp_adapter_names()` - adapters enabled via settings (new) Related: #43104, #45928 Release Notes: - Fixed an issue where not all LSP adapters would be suggested for completion, or recognized as valid in `settings.json` --------- Co-authored-by: Ben Kunkle --- .../src/json_schema_store.rs | 29 ++++++++++++++++--- crates/language/src/language_registry.rs | 11 +++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/crates/json_schema_store/src/json_schema_store.rs b/crates/json_schema_store/src/json_schema_store.rs index 299fe7b994e093b356e1024f5d2f5de003324cb0..92d41c1b164ed821c36d661fd2389d89f62a1e03 100644 --- a/crates/json_schema_store/src/json_schema_store.rs +++ b/crates/json_schema_store/src/json_schema_store.rs @@ -3,7 +3,10 @@ use std::sync::{Arc, LazyLock}; use anyhow::{Context as _, Result}; use collections::HashMap; use gpui::{App, AsyncApp, BorrowAppContext as _, Entity, Task, WeakEntity}; -use language::{LanguageRegistry, LspAdapterDelegate, language_settings::AllLanguageSettings}; +use language::{ + LanguageRegistry, LanguageServerName, LspAdapterDelegate, + language_settings::AllLanguageSettings, +}; use parking_lot::RwLock; use project::{LspStore, lsp_store::LocalLspAdapterDelegate}; use settings::{LSP_SETTINGS_SCHEMA_URL_PREFIX, Settings as _, SettingsLocation}; @@ -244,6 +247,9 @@ async fn resolve_dynamic_schema( .all_lsp_adapters() .into_iter() .find(|adapter| adapter.name().as_ref() as &str == lsp_name) + .or_else(|| { + languages.load_available_lsp_adapter(&LanguageServerName::from(lsp_name)) + }) .with_context(|| format!("LSP adapter not found: {}", lsp_name))?; let delegate: Arc = cx @@ -281,11 +287,26 @@ async fn resolve_dynamic_schema( }) } "settings" => { - let lsp_adapter_names = languages + let mut lsp_adapter_names: Vec = languages .all_lsp_adapters() .into_iter() - .map(|adapter| adapter.name().to_string()) - .collect::>(); + .map(|adapter| adapter.name()) + .chain(languages.available_lsp_adapter_names().into_iter()) + .map(|name| name.to_string()) + .collect(); + + let mut i = 0; + while i < lsp_adapter_names.len() { + let mut j = i + 1; + while j < lsp_adapter_names.len() { + if lsp_adapter_names[i] == lsp_adapter_names[j] { + lsp_adapter_names.swap_remove(j); + } else { + j += 1; + } + } + i += 1; + } cx.update(|cx| { let font_names = &cx.text_system().all_font_names(); diff --git a/crates/language/src/language_registry.rs b/crates/language/src/language_registry.rs index 339887274bcfec12e217acb23803440e8a52ef4b..226eaf544e46b384884f015cdcae77f4ffc71662 100644 --- a/crates/language/src/language_registry.rs +++ b/crates/language/src/language_registry.rs @@ -414,6 +414,17 @@ impl LanguageRegistry { state.available_lsp_adapters.contains_key(name) } + /// Returns the names of all available LSP adapters (registered via `register_available_lsp_adapter`). + /// These are adapters that are not bound to a specific language but can be enabled via settings. + pub fn available_lsp_adapter_names(&self) -> Vec { + self.state + .read() + .available_lsp_adapters + .keys() + .cloned() + .collect() + } + pub fn register_lsp_adapter(&self, language_name: LanguageName, adapter: Arc) { let mut state = self.state.write();