From e1a786993889db1703c428bc0cd0ca4a42ba04d2 Mon Sep 17 00:00:00 2001 From: Cole Miller Date: Fri, 4 Jul 2025 21:39:57 -0400 Subject: [PATCH] wip --- crates/dap/src/registry.rs | 26 ++-- crates/dap_adapters/schemas/JavaScript.json | 140 +++++++----------- crates/dap_adapters/src/update_schemas.rs | 22 ++- crates/languages/src/json.rs | 11 +- crates/task/src/adapter_schema.rs | 18 --- crates/task/src/debug_format.rs | 150 ++++++++++---------- crates/task/src/task.rs | 2 - 7 files changed, 161 insertions(+), 208 deletions(-) delete mode 100644 crates/task/src/adapter_schema.rs diff --git a/crates/dap/src/registry.rs b/crates/dap/src/registry.rs index 9435b16b924e43406d5ed99c864df78c179f27b1..5105849b0f76c67c2b8a804ce0e11b0991ba5a5b 100644 --- a/crates/dap/src/registry.rs +++ b/crates/dap/src/registry.rs @@ -4,12 +4,10 @@ use collections::FxHashMap; use gpui::{App, Global, SharedString}; use language::LanguageName; use parking_lot::RwLock; -use task::{ - AdapterSchema, AdapterSchemas, DebugRequest, DebugScenario, SpawnInTerminal, TaskTemplate, -}; +use task::{DebugRequest, DebugScenario, SpawnInTerminal, TaskTemplate}; use crate::adapters::{DebugAdapter, DebugAdapterName}; -use std::{collections::BTreeMap, sync::Arc}; +use std::{borrow::Cow, collections::BTreeMap, sync::Arc}; /// Given a user build configuration, locator creates a fill-in debug target ([DebugScenario]) on behalf of the user. #[async_trait] @@ -63,19 +61,13 @@ impl DapRegistry { .and_then(|adapter| adapter.adapter_language_name()) } - pub async fn adapters_schema(&self) -> task::AdapterSchemas { - let mut schemas = AdapterSchemas(vec![]); - - let adapters = self.0.read().adapters.clone(); - - for (name, adapter) in adapters.into_iter() { - schemas.0.push(AdapterSchema { - adapter: name.into(), - schema: adapter.dap_schema(), - }); - } - - schemas + pub async fn adapter_schemas(&self) -> Vec<(SharedString, Cow<'static, serde_json::Value>)> { + self.0 + .read() + .adapters + .iter() + .map(|(name, adapter)| (name.0.clone(), adapter.dap_schema())) + .collect() } pub fn locators(&self) -> FxHashMap> { diff --git a/crates/dap_adapters/schemas/JavaScript.json b/crates/dap_adapters/schemas/JavaScript.json index 41c61745603d4f7cf642e20630d80660606a75f0..d7a15ea35bc152d0b785c20485aba6f93a3fb064 100644 --- a/crates/dap_adapters/schemas/JavaScript.json +++ b/crates/dap_adapters/schemas/JavaScript.json @@ -4,14 +4,10 @@ "if": { "properties": { "type": { - "enum": [ - "pwa-node" - ] + "const": "pwa-node" }, "request": { - "enum": [ - "launch" - ] + "const": "launch" } }, "required": [ @@ -412,14 +408,10 @@ "if": { "properties": { "type": { - "enum": [ - "pwa-node" - ] + "const": "pwa-node" }, "request": { - "enum": [ - "attach" - ] + "const": "attach" } }, "required": [ @@ -757,14 +749,10 @@ "if": { "properties": { "type": { - "enum": [ - "node" - ] + "const": "node" }, "request": { - "enum": [ - "launch" - ] + "const": "launch" } }, "required": [ @@ -1165,14 +1153,10 @@ "if": { "properties": { "type": { - "enum": [ - "node" - ] + "const": "node" }, "request": { - "enum": [ - "attach" - ] + "const": "attach" } }, "required": [ @@ -1510,14 +1494,10 @@ "if": { "properties": { "type": { - "enum": [ - "node-terminal" - ] + "const": "node-terminal" }, "request": { - "enum": [ - "launch" - ] + "const": "launch" } }, "required": [ @@ -1798,14 +1778,10 @@ "if": { "properties": { "type": { - "enum": [ - "pwa-extensionHost" - ] + "const": "pwa-extensionHost" }, "request": { - "enum": [ - "launch" - ] + "const": "launch" } }, "required": [ @@ -3098,14 +3074,10 @@ "if": { "properties": { "type": { - "enum": [ - "extensionHost" - ] + "const": "extensionHost" }, "request": { - "enum": [ - "launch" - ] + "const": "launch" } }, "required": [ @@ -4398,14 +4370,10 @@ "if": { "properties": { "type": { - "enum": [ - "pwa-chrome" - ] + "const": "pwa-chrome" }, "request": { - "enum": [ - "launch" - ] + "const": "launch" } }, "required": [ @@ -5436,14 +5404,10 @@ "if": { "properties": { "type": { - "enum": [ - "pwa-chrome" - ] + "const": "pwa-chrome" }, "request": { - "enum": [ - "attach" - ] + "const": "attach" } }, "required": [ @@ -6428,14 +6392,10 @@ "if": { "properties": { "type": { - "enum": [ - "chrome" - ] + "const": "chrome" }, "request": { - "enum": [ - "launch" - ] + "const": "launch" } }, "required": [ @@ -7466,14 +7426,10 @@ "if": { "properties": { "type": { - "enum": [ - "chrome" - ] + "const": "chrome" }, "request": { - "enum": [ - "attach" - ] + "const": "attach" } }, "required": [ @@ -8458,14 +8414,10 @@ "if": { "properties": { "type": { - "enum": [ - "pwa-msedge" - ] + "const": "pwa-msedge" }, "request": { - "enum": [ - "launch" - ] + "const": "launch" } }, "required": [ @@ -9506,14 +9458,10 @@ "if": { "properties": { "type": { - "enum": [ - "pwa-msedge" - ] + "const": "pwa-msedge" }, "request": { - "enum": [ - "attach" - ] + "const": "attach" } }, "required": [ @@ -10510,14 +10458,10 @@ "if": { "properties": { "type": { - "enum": [ - "msedge" - ] + "const": "msedge" }, "request": { - "enum": [ - "launch" - ] + "const": "launch" } }, "required": [ @@ -11558,14 +11502,10 @@ "if": { "properties": { "type": { - "enum": [ - "msedge" - ] + "const": "msedge" }, "request": { - "enum": [ - "attach" - ] + "const": "attach" } }, "required": [ @@ -12557,6 +12497,26 @@ } } } + }, + { + "properties": { + "type": { + "enum": [ + "pwa-node", + "node", + "node-terminal", + "pwa-extensionHost", + "extensionHost", + "pwa-chrome", + "chrome", + "pwa-msedge", + "msedge" + ] + } + }, + "required": [ + "type" + ] } ] } diff --git a/crates/dap_adapters/src/update_schemas.rs b/crates/dap_adapters/src/update_schemas.rs index 0185fc5f98b3f596dfcca5cb36b193b06e2a7ecc..949825706a0cf61c8d6d26c26034868d1d206cf1 100644 --- a/crates/dap_adapters/src/update_schemas.rs +++ b/crates/dap_adapters/src/update_schemas.rs @@ -88,7 +88,13 @@ fn main() { let package_json: PackageJson = serde_json::from_value(package_json).unwrap(); - let alternatives = package_json + let types = package_json + .contributes + .debuggers + .iter() + .map(|debugger| debugger.r#type.clone()) + .collect::>(); + let mut conjuncts = package_json .contributes .debuggers .into_iter() @@ -109,10 +115,10 @@ fn main() { "if": { "properties": { "type": { - "enum": [r#type] + "const": r#type }, "request": { - "enum": [request] + "const": request } }, "required": ["type", "request"] @@ -123,8 +129,16 @@ fn main() { .collect::>() }) .collect::>(); + conjuncts.push(json_schema!({ + "properties": { + "type": { + "enum": types + } + }, + "required": ["type"] + })); let schema = json_schema!({ - "allOf": alternatives + "allOf": conjuncts }); let mut schema = serde_json::to_string_pretty(&schema.to_value()).unwrap(); diff --git a/crates/languages/src/json.rs b/crates/languages/src/json.rs index 7a3300eb010d9da30111023e660ef56a2070ea9e..5fa540337a90563b3c0430326b7d8cc13d7c16d5 100644 --- a/crates/languages/src/json.rs +++ b/crates/languages/src/json.rs @@ -5,7 +5,7 @@ use async_trait::async_trait; use collections::HashMap; use dap::DapRegistry; use futures::StreamExt; -use gpui::{App, AsyncApp, Task}; +use gpui::{App, AsyncApp, SharedString, Task}; use http_client::github::{GitHubLspBinaryVersion, latest_github_release}; use language::{ ContextProvider, LanguageRegistry, LanguageToolchainStore, LocalFile as _, LspAdapter, @@ -23,13 +23,14 @@ use smol::{ }; use std::{ any::Any, + borrow::Cow, env::consts, ffi::OsString, path::{Path, PathBuf}, str::FromStr, sync::Arc, }; -use task::{AdapterSchemas, TaskTemplate, TaskTemplates, VariableName}; +use task::{TaskTemplate, TaskTemplates, VariableName}; use util::{ResultExt, archive::extract_zip, fs::remove_matching, maybe, merge_json_value_into}; use crate::PackageJsonData; @@ -153,7 +154,7 @@ impl JsonLspAdapter { fn get_workspace_config( language_names: Vec, - adapter_schemas: AdapterSchemas, + adapter_schemas: Vec<(SharedString, Cow<'static, serde_json::Value>)>, cx: &mut App, ) -> Value { let keymap_schema = KeymapFile::generate_json_schema_for_registered_actions(cx); @@ -167,7 +168,7 @@ impl JsonLspAdapter { ); let tasks_schema = task::TaskTemplates::generate_json_schema(); - let debug_schema = task::DebugTaskFile::generate_json_schema(&adapter_schemas); + let debug_schema = task::DebugTaskFile::generate_json_schema(adapter_schemas); let snippets_schema = snippet_provider::format::VsSnippetsFile::generate_json_schema(); let tsconfig_schema = serde_json::Value::from_str(TSCONFIG_SCHEMA).unwrap(); let package_json_schema = serde_json::Value::from_str(PACKAGE_JSON_SCHEMA).unwrap(); @@ -258,7 +259,7 @@ impl JsonLspAdapter { let adapter_schemas = cx .read_global::(|dap_registry, _| dap_registry.to_owned())? - .adapters_schema() + .adapter_schemas() .await; let config = cx.update(|cx| { diff --git a/crates/task/src/adapter_schema.rs b/crates/task/src/adapter_schema.rs deleted file mode 100644 index c4495725d11d1f37316d9440f28bfcabcf512380..0000000000000000000000000000000000000000 --- a/crates/task/src/adapter_schema.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::borrow::Cow; - -use gpui::SharedString; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -/// JSON schema for a specific adapter -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] -pub struct AdapterSchema { - /// The adapter name identifier - pub adapter: SharedString, - /// The JSON schema for this adapter's configuration - pub schema: Cow<'static, serde_json::Value>, -} - -#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] -#[serde(transparent)] -pub struct AdapterSchemas(pub Vec); diff --git a/crates/task/src/debug_format.rs b/crates/task/src/debug_format.rs index f20f55975e7a1d178b899b7cc89d19676d7f27cf..5cd8e2550b4f7ddb16044b32043d3e9f6ddc3a6c 100644 --- a/crates/task/src/debug_format.rs +++ b/crates/task/src/debug_format.rs @@ -4,12 +4,32 @@ use gpui::SharedString; use log as _; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use std::net::Ipv4Addr; use std::path::PathBuf; -use util::{debug_panic, schemars::add_new_subschema}; - -use crate::{TaskTemplate, adapter_schema::AdapterSchemas}; - +use std::{borrow::Cow, net::Ipv4Addr}; +use util::schemars::add_new_subschema; + +use crate::TaskTemplate; + +// FIXME +//"tcp_connection": { +// "type": "object", +// "description": "Optional TCP connection information for connecting to an already running debug adapter", +// "properties": { +// "port": { +// "type": "integer", +// "description": "The port that the debug adapter is listening on (default: auto-find open port)" +// }, +// "host": { +// "type": "string", +// "pattern": "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$", +// "description": "The host that the debug adapter is listening to (default: 127.0.0.1)" +// }, +// "timeout": { +// "type": "integer", +// "description": "The max amount of time in milliseconds to connect to a tcp DAP before returning an error (default: 2000ms)" +// } +// } +//} /// Represents the host information of the debug adapter #[derive(Default, Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)] pub struct TcpArgumentsTemplate { @@ -281,51 +301,54 @@ pub struct DebugScenario { } /// A group of Debug Tasks defined in a JSON file. -#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] pub struct DebugTaskFile(pub Vec); impl DebugTaskFile { - pub fn generate_json_schema(schemas: &AdapterSchemas) -> serde_json::Value { + pub fn generate_json_schema( + adapter_schemas: Vec<(SharedString, Cow<'static, serde_json::Value>)>, + ) -> serde_json::Value { let mut generator = schemars::generate::SchemaSettings::draft2019_09().into_generator(); - let mut build_task_value = BuildTaskDefinition::json_schema(&mut generator).to_value(); - - if let Some(template_object) = build_task_value - .get_mut("anyOf") - .and_then(|array| array.as_array_mut()) - .and_then(|array| array.get_mut(1)) - { - if let Some(properties) = template_object - .get_mut("properties") - .and_then(|value| value.as_object_mut()) - { - if properties.remove("label").is_none() { - debug_panic!( - "Generated TaskTemplate json schema did not have expected 'label' field. \ - Schema of 2nd alternative is: {template_object:?}" - ); - } - } - - if let Some(arr) = template_object - .get_mut("required") - .and_then(|array| array.as_array_mut()) - { - arr.retain(|v| v.as_str() != Some("label")); - } - } else { - debug_panic!( - "Generated TaskTemplate json schema did not match expectations. \ - Schema is: {build_task_value:?}" - ); - } - - let adapter_conditions = schemas - .0 + // FIXME what is this doing + // if let Some(template_object) = build_task_schema + // .get_mut("anyOf") + // .and_then(|array| array.as_array_mut()) + // .and_then(|array| array.get_mut(1)) + // { + // if let Some(properties) = template_object + // .get_mut("properties") + // .and_then(|value| value.as_object_mut()) + // { + // if properties.remove("label").is_none() { + // debug_panic!( + // "Generated TaskTemplate json schema did not have expected 'label' field. \ + // Schema of 2nd alternative is: {template_object:?}" + // ); + // } + // } + + // if let Some(arr) = template_object + // .get_mut("required") + // .and_then(|array| array.as_array_mut()) + // { + // arr.retain(|v| v.as_str() != Some("label")); + // } + // } else { + // debug_panic!( + // "Generated TaskTemplate json schema did not match expectations. \ + // Schema is: {build_task_schema:?}" + // ); + // } + + let adapter_names = adapter_schemas + .iter() + .map(|(adapter_name, _)| adapter_name.clone()) + .collect::>(); + let adapter_conditions = adapter_schemas .iter() - .map(|adapter_schema| { - let adapter_name = adapter_schema.adapter.to_string(); + .map(|(adapter_name, schema)| { add_new_subschema( &mut generator, &format!("{adapter_name}DebugSettings"), @@ -335,16 +358,23 @@ impl DebugTaskFile { "adapter": { "const": adapter_name } } }, - "then": adapter_schema.schema + "then": schema }), ) }) .collect::>(); + let build_task_schema = BuildTaskDefinition::json_schema(&mut generator).to_value(); let build_task_definition_ref = add_new_subschema( &mut generator, BuildTaskDefinition::schema_name().as_ref(), - build_task_value, + build_task_schema, + ); + let tcp_connection_schema = TcpArgumentsTemplate::json_schema(&mut generator).to_value(); + let tcp_connection_definition_ref = add_new_subschema( + &mut generator, + TcpArgumentsTemplate::schema_name().as_ref(), + tcp_connection_schema, ); let meta_schema = generator @@ -362,16 +392,10 @@ impl DebugTaskFile { "items": { "type": "object", "required": ["adapter", "label"], - // TODO: Uncommenting this will cause json-language-server to provide warnings for - // unrecognized properties. It should be enabled if/when there's an adapter JSON - // schema that's comprehensive. In order to not get warnings for the other schemas, - // `additionalProperties` or `unevaluatedProperties` (to handle "allOf" etc style - // schema combinations) could be set to `true` for that schema. - // - // "unevaluatedProperties": false, + "unevaluatedProperties": false, "properties": { "adapter": { - "type": "string", + "enum": adapter_names, "description": "The name of the debug adapter" }, "label": { @@ -379,25 +403,7 @@ impl DebugTaskFile { "description": "The name of the debug configuration" }, "build": build_task_definition_ref, - "tcp_connection": { - "type": "object", - "description": "Optional TCP connection information for connecting to an already running debug adapter", - "properties": { - "port": { - "type": "integer", - "description": "The port that the debug adapter is listening on (default: auto-find open port)" - }, - "host": { - "type": "string", - "pattern": "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$", - "description": "The host that the debug adapter is listening to (default: 127.0.0.1)" - }, - "timeout": { - "type": "integer", - "description": "The max amount of time in milliseconds to connect to a tcp DAP before returning an error (default: 2000ms)" - } - } - } + "tcp_connection": tcp_connection_definition_ref, }, "allOf": adapter_conditions }, diff --git a/crates/task/src/task.rs b/crates/task/src/task.rs index da2d25902bd2343beacaf031b31d5c65fed5a459..4586b0cacc83863d27562383cb3e3fb70c78e247 100644 --- a/crates/task/src/task.rs +++ b/crates/task/src/task.rs @@ -1,6 +1,5 @@ //! Baseline interface of Tasks in Zed: all tasks in Zed are intended to use those for implementing their own logic. -mod adapter_schema; mod debug_format; mod serde_helpers; mod shell_builder; @@ -17,7 +16,6 @@ use std::borrow::Cow; use std::path::PathBuf; use std::str::FromStr; -pub use adapter_schema::{AdapterSchema, AdapterSchemas}; pub use debug_format::{ AttachRequest, BuildTaskDefinition, DebugRequest, DebugScenario, DebugTaskFile, LaunchRequest, Request, TcpArgumentsTemplate, ZedDebugConfig,