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 <ben@zed.dev>
This commit is contained in:
Bae Seokjae 2026-02-12 23:58:38 +09:00 committed by GitHub
parent 839dac198f
commit c1907c94d2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 36 additions and 4 deletions

View file

@ -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<dyn LspAdapterDelegate> = cx
@ -281,11 +287,26 @@ async fn resolve_dynamic_schema(
})
}
"settings" => {
let lsp_adapter_names = languages
let mut lsp_adapter_names: Vec<String> = languages
.all_lsp_adapters()
.into_iter()
.map(|adapter| adapter.name().to_string())
.collect::<Vec<_>>();
.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();

View file

@ -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<LanguageServerName> {
self.state
.read()
.available_lsp_adapters
.keys()
.cloned()
.collect()
}
pub fn register_lsp_adapter(&self, language_name: LanguageName, adapter: Arc<dyn LspAdapter>) {
let mut state = self.state.write();