Detailed changes
@@ -3,8 +3,9 @@ use std::{str::FromStr, sync::Arc};
use anyhow::{Context as _, Result};
use gpui::{App, AsyncApp, BorrowAppContext as _, Entity, WeakEntity};
-use language::LanguageRegistry;
+use language::{LanguageRegistry, language_settings::all_language_settings};
use project::LspStore;
+use util::schemars::{AllowTrailingCommas, DefaultDenyUnknownFields};
// Origin: https://github.com/SchemaStore/schemastore
const TSCONFIG_SCHEMA: &str = include_str!("schemas/tsconfig.json");
@@ -159,14 +160,35 @@ pub fn resolve_schema_request_inner(
}
}
"snippets" => snippet_provider::format::VsSnippetsFile::generate_json_schema(),
+ "jsonc" => jsonc_schema(),
_ => {
- anyhow::bail!("Unrecognized builtin JSON schema: {}", schema_name);
+ anyhow::bail!("Unrecognized builtin JSON schema: {schema_name}");
}
};
Ok(schema)
}
-pub fn all_schema_file_associations(cx: &mut App) -> serde_json::Value {
+const JSONC_LANGUAGE_NAME: &str = "JSONC";
+
+pub fn all_schema_file_associations(
+ languages: &Arc<LanguageRegistry>,
+ cx: &mut App,
+) -> serde_json::Value {
+ let extension_globs = languages
+ .available_language_for_name(JSONC_LANGUAGE_NAME)
+ .map(|language| language.matcher().path_suffixes.clone())
+ .into_iter()
+ .flatten()
+ // Path suffixes can be entire file names or just their extensions.
+ .flat_map(|path_suffix| [format!("*.{path_suffix}"), path_suffix]);
+ let override_globs = all_language_settings(None, cx)
+ .file_types
+ .get(JSONC_LANGUAGE_NAME)
+ .into_iter()
+ .flat_map(|(_, glob_strings)| glob_strings)
+ .cloned();
+ let jsonc_globs = extension_globs.chain(override_globs).collect::<Vec<_>>();
+
let mut file_associations = serde_json::json!([
{
"fileMatch": [
@@ -211,6 +233,10 @@ pub fn all_schema_file_associations(cx: &mut App) -> serde_json::Value {
"fileMatch": ["package.json"],
"url": "zed://schemas/package_json"
},
+ {
+ "fileMatch": &jsonc_globs,
+ "url": "zed://schemas/jsonc"
+ },
]);
#[cfg(debug_assertions)]
@@ -233,7 +259,7 @@ pub fn all_schema_file_associations(cx: &mut App) -> serde_json::Value {
let file_name = normalized_action_name_to_file_name(normalized_name.clone());
serde_json::json!({
"fileMatch": [file_name],
- "url": format!("zed://schemas/action/{}", normalized_name)
+ "url": format!("zed://schemas/action/{normalized_name}")
})
}),
);
@@ -249,6 +275,26 @@ fn package_json_schema() -> serde_json::Value {
serde_json::Value::from_str(PACKAGE_JSON_SCHEMA).unwrap()
}
+fn jsonc_schema() -> serde_json::Value {
+ let generator = schemars::generate::SchemaSettings::draft2019_09()
+ .with_transform(DefaultDenyUnknownFields)
+ .with_transform(AllowTrailingCommas)
+ .into_generator();
+ let meta_schema = generator
+ .settings()
+ .meta_schema
+ .as_ref()
+ .expect("meta_schema should be present in schemars settings")
+ .to_string();
+ let defs = generator.definitions();
+ let schema = schemars::json_schema!({
+ "$schema": meta_schema,
+ "allowTrailingCommas": true,
+ "$defs": defs,
+ });
+ serde_json::to_value(schema).unwrap()
+}
+
fn generate_inspector_style_schema() -> serde_json::Value {
let schema = schemars::generate::SchemaSettings::draft2019_09()
.with_transform(util::schemars::DefaultDenyUnknownFields)
@@ -745,7 +745,7 @@ impl LanguageRegistry {
self: &Arc<Self>,
path: &Path,
content: Option<&Rope>,
- user_file_types: Option<&FxHashMap<Arc<str>, GlobSet>>,
+ user_file_types: Option<&FxHashMap<Arc<str>, (GlobSet, Vec<String>)>>,
) -> Option<AvailableLanguage> {
let filename = path.file_name().and_then(|filename| filename.to_str());
// `Path.extension()` returns None for files with a leading '.'
@@ -788,7 +788,7 @@ impl LanguageRegistry {
let path_matches_custom_suffix = || {
user_file_types
.and_then(|types| types.get(language_name.as_ref()))
- .map_or(None, |custom_suffixes| {
+ .map_or(None, |(custom_suffixes, _)| {
path_suffixes
.iter()
.find(|(_, candidate)| custom_suffixes.is_match_candidate(candidate))
@@ -51,7 +51,7 @@ pub struct AllLanguageSettings {
pub edit_predictions: EditPredictionSettings,
pub defaults: LanguageSettings,
languages: HashMap<LanguageName, LanguageSettings>,
- pub(crate) file_types: FxHashMap<Arc<str>, GlobSet>,
+ pub file_types: FxHashMap<Arc<str>, (GlobSet, Vec<String>)>,
}
#[derive(Debug, Clone, PartialEq)]
@@ -656,7 +656,7 @@ impl settings::Settings for AllLanguageSettings {
let enabled_in_text_threads = edit_predictions.enabled_in_text_threads.unwrap();
- let mut file_types: FxHashMap<Arc<str>, GlobSet> = FxHashMap::default();
+ let mut file_types: FxHashMap<Arc<str>, (GlobSet, Vec<String>)> = FxHashMap::default();
for (language, patterns) in all_languages.file_types.iter().flatten() {
let mut builder = GlobSetBuilder::new();
@@ -665,7 +665,10 @@ impl settings::Settings for AllLanguageSettings {
builder.add(Glob::new(pattern).unwrap());
}
- file_types.insert(language.clone(), builder.build().unwrap());
+ file_types.insert(
+ language.clone(),
+ (builder.build().unwrap(), patterns.0.clone()),
+ );
}
Self {
@@ -7,8 +7,8 @@ use futures::StreamExt;
use gpui::{App, AsyncApp, Task};
use http_client::github::{GitHubLspBinaryVersion, latest_github_release};
use language::{
- ContextProvider, LanguageName, LocalFile as _, LspAdapter, LspAdapterDelegate, LspInstaller,
- Toolchain,
+ ContextProvider, LanguageName, LanguageRegistry, LocalFile as _, LspAdapter,
+ LspAdapterDelegate, LspInstaller, Toolchain,
};
use lsp::{LanguageServerBinary, LanguageServerName, Uri};
use node_runtime::{NodeRuntime, VersionStrategy};
@@ -129,14 +129,15 @@ fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
}
pub struct JsonLspAdapter {
+ languages: Arc<LanguageRegistry>,
node: NodeRuntime,
}
impl JsonLspAdapter {
const PACKAGE_NAME: &str = "vscode-langservers-extracted";
- pub fn new(node: NodeRuntime) -> Self {
- Self { node }
+ pub fn new(languages: Arc<LanguageRegistry>, node: NodeRuntime) -> Self {
+ Self { languages, node }
}
}
@@ -255,7 +256,7 @@ impl LspAdapter for JsonLspAdapter {
cx: &mut AsyncApp,
) -> Result<Value> {
let mut config = cx.update(|cx| {
- let schemas = json_schema_store::all_schema_file_associations(cx);
+ let schemas = json_schema_store::all_schema_file_associations(&self.languages, cx);
// This can be viewed via `dev: open language server logs` -> `json-language-server` ->
// `Server Info`
@@ -89,7 +89,7 @@ pub fn init(languages: Arc<LanguageRegistry>, fs: Arc<dyn Fs>, node: NodeRuntime
let go_context_provider = Arc::new(go::GoContextProvider);
let go_lsp_adapter = Arc::new(go::GoLspAdapter);
let json_context_provider = Arc::new(JsonTaskProvider);
- let json_lsp_adapter = Arc::new(json::JsonLspAdapter::new(node.clone()));
+ let json_lsp_adapter = Arc::new(json::JsonLspAdapter::new(languages.clone(), node.clone()));
let node_version_lsp_adapter = Arc::new(json::NodeVersionAdapter);
let py_lsp_adapter = Arc::new(python::PyLspAdapter::new());
let ty_lsp_adapter = Arc::new(python::TyLspAdapter::new(fs.clone()));