extension: Update DAP extension API (#32448)
- DAP schemas will be stored in `debug_adapters_schemas` subdirectory in extension work dir. - Added Debug Config integration and such. Release Notes: - N/A
This commit is contained in:
parent
41e9f3148c
commit
8df6ce2aac
28 changed files with 620 additions and 47 deletions
|
@ -139,6 +139,7 @@ fn manifest() -> ExtensionManifest {
|
|||
args: vec!["hello!".into()],
|
||||
}],
|
||||
debug_adapters: Default::default(),
|
||||
debug_locators: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1348,6 +1348,11 @@ impl ExtensionStore {
|
|||
this.proxy
|
||||
.register_debug_adapter(extension.clone(), debug_adapter.clone());
|
||||
}
|
||||
|
||||
for debug_adapter in &manifest.debug_adapters {
|
||||
this.proxy
|
||||
.register_debug_locator(extension.clone(), debug_adapter.clone());
|
||||
}
|
||||
}
|
||||
|
||||
this.wasm_extensions.extend(wasm_extensions);
|
||||
|
|
|
@ -163,6 +163,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
|
|||
snippets: None,
|
||||
capabilities: Vec::new(),
|
||||
debug_adapters: Default::default(),
|
||||
debug_locators: Default::default(),
|
||||
}),
|
||||
dev: false,
|
||||
},
|
||||
|
@ -193,6 +194,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
|
|||
snippets: None,
|
||||
capabilities: Vec::new(),
|
||||
debug_adapters: Default::default(),
|
||||
debug_locators: Default::default(),
|
||||
}),
|
||||
dev: false,
|
||||
},
|
||||
|
@ -368,6 +370,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
|
|||
snippets: None,
|
||||
capabilities: Vec::new(),
|
||||
debug_adapters: Default::default(),
|
||||
debug_locators: Default::default(),
|
||||
}),
|
||||
dev: false,
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@ pub mod wit;
|
|||
use crate::ExtensionManifest;
|
||||
use anyhow::{Context as _, Result, anyhow, bail};
|
||||
use async_trait::async_trait;
|
||||
use dap::{DebugRequest, StartDebuggingRequestArgumentsRequest};
|
||||
use extension::{
|
||||
CodeLabel, Command, Completion, ContextServerConfiguration, DebugAdapterBinary,
|
||||
DebugTaskDefinition, ExtensionHostProxy, KeyValueStoreDelegate, ProjectDelegate, SlashCommand,
|
||||
|
@ -32,6 +33,7 @@ use std::{
|
|||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use task::{DebugScenario, SpawnInTerminal, TaskTemplate, ZedDebugConfig};
|
||||
use wasmtime::{
|
||||
CacheStore, Engine, Store,
|
||||
component::{Component, ResourceTable},
|
||||
|
@ -399,14 +401,76 @@ impl extension::Extension for WasmExtension {
|
|||
})
|
||||
.await
|
||||
}
|
||||
async fn dap_request_kind(
|
||||
&self,
|
||||
dap_name: Arc<str>,
|
||||
config: serde_json::Value,
|
||||
) -> Result<StartDebuggingRequestArgumentsRequest> {
|
||||
self.call(|extension, store| {
|
||||
async move {
|
||||
let kind = extension
|
||||
.call_dap_request_kind(store, dap_name, config)
|
||||
.await?
|
||||
.map_err(|err| store.data().extension_error(err))?;
|
||||
Ok(kind.into())
|
||||
}
|
||||
.boxed()
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_dap_schema(&self) -> Result<serde_json::Value> {
|
||||
async fn dap_config_to_scenario(
|
||||
&self,
|
||||
config: ZedDebugConfig,
|
||||
worktree: Arc<dyn WorktreeDelegate>,
|
||||
) -> Result<DebugScenario> {
|
||||
self.call(|extension, store| {
|
||||
async move {
|
||||
let resource = store.data_mut().table().push(worktree)?;
|
||||
let kind = extension
|
||||
.call_dap_config_to_scenario(store, config, resource)
|
||||
.await?
|
||||
.map_err(|err| store.data().extension_error(err))?;
|
||||
Ok(kind)
|
||||
}
|
||||
.boxed()
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn dap_locator_create_scenario(
|
||||
&self,
|
||||
locator_name: String,
|
||||
build_config_template: TaskTemplate,
|
||||
resolved_label: String,
|
||||
debug_adapter_name: String,
|
||||
) -> Result<Option<DebugScenario>> {
|
||||
self.call(|extension, store| {
|
||||
async move {
|
||||
extension
|
||||
.call_dap_schema(store)
|
||||
.call_dap_locator_create_scenario(
|
||||
store,
|
||||
locator_name,
|
||||
build_config_template,
|
||||
resolved_label,
|
||||
debug_adapter_name,
|
||||
)
|
||||
.await
|
||||
.and_then(|schema| serde_json::to_value(schema).map_err(|err| err.to_string()))
|
||||
}
|
||||
.boxed()
|
||||
})
|
||||
.await
|
||||
}
|
||||
async fn run_dap_locator(
|
||||
&self,
|
||||
locator_name: String,
|
||||
config: SpawnInTerminal,
|
||||
) -> Result<DebugRequest> {
|
||||
self.call(|extension, store| {
|
||||
async move {
|
||||
extension
|
||||
.call_run_dap_locator(store, locator_name, config)
|
||||
.await?
|
||||
.map_err(|err| store.data().extension_error(err))
|
||||
}
|
||||
.boxed()
|
||||
|
|
|
@ -7,10 +7,14 @@ mod since_v0_3_0;
|
|||
mod since_v0_4_0;
|
||||
mod since_v0_5_0;
|
||||
mod since_v0_6_0;
|
||||
use dap::DebugRequest;
|
||||
use extension::{DebugTaskDefinition, KeyValueStoreDelegate, WorktreeDelegate};
|
||||
use language::LanguageName;
|
||||
use lsp::LanguageServerName;
|
||||
use release_channel::ReleaseChannel;
|
||||
use task::{DebugScenario, SpawnInTerminal, TaskTemplate, ZedDebugConfig};
|
||||
|
||||
use crate::wasm_host::wit::since_v0_6_0::dap::StartDebuggingRequestArgumentsRequest;
|
||||
|
||||
use super::{WasmState, wasm_engine};
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
|
@ -922,18 +926,88 @@ impl Extension {
|
|||
_ => anyhow::bail!("`get_dap_binary` not available prior to v0.6.0"),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn call_dap_schema(&self, store: &mut Store<WasmState>) -> Result<String, String> {
|
||||
pub async fn call_dap_request_kind(
|
||||
&self,
|
||||
store: &mut Store<WasmState>,
|
||||
adapter_name: Arc<str>,
|
||||
config: serde_json::Value,
|
||||
) -> Result<Result<StartDebuggingRequestArgumentsRequest, String>> {
|
||||
match self {
|
||||
Extension::V0_6_0(ext) => {
|
||||
let schema = ext
|
||||
.call_dap_schema(store)
|
||||
.await
|
||||
.map_err(|err| err.to_string())?;
|
||||
let config =
|
||||
serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
|
||||
let dap_binary = ext
|
||||
.call_dap_request_kind(store, &adapter_name, &config)
|
||||
.await?
|
||||
.map_err(|e| anyhow!("{e:?}"))?;
|
||||
|
||||
schema
|
||||
Ok(Ok(dap_binary))
|
||||
}
|
||||
_ => Err("`get_dap_binary` not available prior to v0.6.0".to_string()),
|
||||
_ => anyhow::bail!("`dap_request_kind` not available prior to v0.6.0"),
|
||||
}
|
||||
}
|
||||
pub async fn call_dap_config_to_scenario(
|
||||
&self,
|
||||
store: &mut Store<WasmState>,
|
||||
config: ZedDebugConfig,
|
||||
resource: Resource<Arc<dyn WorktreeDelegate>>,
|
||||
) -> Result<Result<DebugScenario, String>> {
|
||||
match self {
|
||||
Extension::V0_6_0(ext) => {
|
||||
let config = config.into();
|
||||
let dap_binary = ext
|
||||
.call_dap_config_to_scenario(store, &config, resource)
|
||||
.await?
|
||||
.map_err(|e| anyhow!("{e:?}"))?;
|
||||
|
||||
Ok(Ok(dap_binary.try_into()?))
|
||||
}
|
||||
_ => anyhow::bail!("`dap_config_to_scenario` not available prior to v0.6.0"),
|
||||
}
|
||||
}
|
||||
pub async fn call_dap_locator_create_scenario(
|
||||
&self,
|
||||
store: &mut Store<WasmState>,
|
||||
locator_name: String,
|
||||
build_config_template: TaskTemplate,
|
||||
resolved_label: String,
|
||||
debug_adapter_name: String,
|
||||
) -> Result<Option<DebugScenario>> {
|
||||
match self {
|
||||
Extension::V0_6_0(ext) => {
|
||||
let build_config_template = build_config_template.into();
|
||||
let dap_binary = ext
|
||||
.call_dap_locator_create_scenario(
|
||||
store,
|
||||
&locator_name,
|
||||
&build_config_template,
|
||||
&resolved_label,
|
||||
&debug_adapter_name,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(dap_binary.map(TryInto::try_into).transpose()?)
|
||||
}
|
||||
_ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
|
||||
}
|
||||
}
|
||||
pub async fn call_run_dap_locator(
|
||||
&self,
|
||||
store: &mut Store<WasmState>,
|
||||
locator_name: String,
|
||||
resolved_build_task: SpawnInTerminal,
|
||||
) -> Result<Result<DebugRequest, String>> {
|
||||
match self {
|
||||
Extension::V0_6_0(ext) => {
|
||||
let build_config_template = resolved_build_task.into();
|
||||
let dap_request = ext
|
||||
.call_run_dap_locator(store, &locator_name, &build_config_template)
|
||||
.await?
|
||||
.map_err(|e| anyhow!("{e:?}"))?;
|
||||
|
||||
Ok(Ok(dap_request.into()))
|
||||
}
|
||||
_ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::wasm_host::wit::since_v0_6_0::{
|
||||
dap::{
|
||||
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest, TcpArguments,
|
||||
TcpArgumentsTemplate,
|
||||
AttachRequest, BuildTaskDefinition, BuildTaskDefinitionTemplatePayload, LaunchRequest,
|
||||
StartDebuggingRequestArguments, TcpArguments, TcpArgumentsTemplate,
|
||||
},
|
||||
slash_command::SlashCommandOutputSection,
|
||||
};
|
||||
|
@ -18,6 +18,7 @@ use extension::{
|
|||
};
|
||||
use futures::{AsyncReadExt, lock::Mutex};
|
||||
use futures::{FutureExt as _, io::BufReader};
|
||||
use gpui::SharedString;
|
||||
use language::{BinaryStatus, LanguageName, language_settings::AllLanguageSettings};
|
||||
use project::project_settings::ProjectSettings;
|
||||
use semantic_version::SemanticVersion;
|
||||
|
@ -25,8 +26,10 @@ use std::{
|
|||
env,
|
||||
net::Ipv4Addr,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
use task::{SpawnInTerminal, ZedDebugConfig};
|
||||
use util::{archive::extract_zip, maybe};
|
||||
use wasmtime::component::{Linker, Resource};
|
||||
|
||||
|
@ -119,6 +122,16 @@ impl From<extension::TcpArgumentsTemplate> for TcpArgumentsTemplate {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<TcpArgumentsTemplate> for extension::TcpArgumentsTemplate {
|
||||
fn from(value: TcpArgumentsTemplate) -> Self {
|
||||
Self {
|
||||
host: value.host.map(Ipv4Addr::from_bits),
|
||||
port: value.port,
|
||||
timeout: value.timeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<extension::DebugTaskDefinition> for DebugTaskDefinition {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(value: extension::DebugTaskDefinition) -> Result<Self, Self::Error> {
|
||||
|
@ -131,6 +144,71 @@ impl TryFrom<extension::DebugTaskDefinition> for DebugTaskDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<task::DebugRequest> for DebugRequest {
|
||||
fn from(value: task::DebugRequest) -> Self {
|
||||
match value {
|
||||
task::DebugRequest::Launch(launch_request) => Self::Launch(launch_request.into()),
|
||||
task::DebugRequest::Attach(attach_request) => Self::Attach(attach_request.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DebugRequest> for task::DebugRequest {
|
||||
fn from(value: DebugRequest) -> Self {
|
||||
match value {
|
||||
DebugRequest::Launch(launch_request) => Self::Launch(launch_request.into()),
|
||||
DebugRequest::Attach(attach_request) => Self::Attach(attach_request.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<task::LaunchRequest> for LaunchRequest {
|
||||
fn from(value: task::LaunchRequest) -> Self {
|
||||
Self {
|
||||
program: value.program,
|
||||
cwd: value.cwd.map(|p| p.to_string_lossy().into_owned()),
|
||||
args: value.args,
|
||||
envs: value.env.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<task::AttachRequest> for AttachRequest {
|
||||
fn from(value: task::AttachRequest) -> Self {
|
||||
Self {
|
||||
process_id: value.process_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LaunchRequest> for task::LaunchRequest {
|
||||
fn from(value: LaunchRequest) -> Self {
|
||||
Self {
|
||||
program: value.program,
|
||||
cwd: value.cwd.map(|p| p.into()),
|
||||
args: value.args,
|
||||
env: value.envs.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<AttachRequest> for task::AttachRequest {
|
||||
fn from(value: AttachRequest) -> Self {
|
||||
Self {
|
||||
process_id: value.process_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ZedDebugConfig> for DebugConfig {
|
||||
fn from(value: ZedDebugConfig) -> Self {
|
||||
Self {
|
||||
label: value.label.into(),
|
||||
adapter: value.adapter.into(),
|
||||
request: value.request.into(),
|
||||
stop_on_entry: value.stop_on_entry,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<DebugAdapterBinary> for extension::DebugAdapterBinary {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(value: DebugAdapterBinary) -> Result<Self, Self::Error> {
|
||||
|
@ -145,6 +223,94 @@ impl TryFrom<DebugAdapterBinary> for extension::DebugAdapterBinary {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<BuildTaskDefinition> for extension::BuildTaskDefinition {
|
||||
fn from(value: BuildTaskDefinition) -> Self {
|
||||
match value {
|
||||
BuildTaskDefinition::ByName(name) => Self::ByName(name.into()),
|
||||
BuildTaskDefinition::Template(build_task_template) => Self::Template {
|
||||
task_template: build_task_template.template.into(),
|
||||
locator_name: build_task_template.locator_name.map(SharedString::from),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<extension::BuildTaskDefinition> for BuildTaskDefinition {
|
||||
fn from(value: extension::BuildTaskDefinition) -> Self {
|
||||
match value {
|
||||
extension::BuildTaskDefinition::ByName(name) => Self::ByName(name.into()),
|
||||
extension::BuildTaskDefinition::Template {
|
||||
task_template,
|
||||
locator_name,
|
||||
} => Self::Template(BuildTaskDefinitionTemplatePayload {
|
||||
template: task_template.into(),
|
||||
locator_name: locator_name.map(String::from),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<BuildTaskTemplate> for extension::BuildTaskTemplate {
|
||||
fn from(value: BuildTaskTemplate) -> Self {
|
||||
Self {
|
||||
label: value.label,
|
||||
command: value.command,
|
||||
args: value.args,
|
||||
env: value.env.into_iter().collect(),
|
||||
cwd: value.cwd,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<extension::BuildTaskTemplate> for BuildTaskTemplate {
|
||||
fn from(value: extension::BuildTaskTemplate) -> Self {
|
||||
Self {
|
||||
label: value.label,
|
||||
command: value.command,
|
||||
args: value.args,
|
||||
env: value.env.into_iter().collect(),
|
||||
cwd: value.cwd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<DebugScenario> for extension::DebugScenario {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: DebugScenario) -> std::result::Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
adapter: value.adapter.into(),
|
||||
label: value.label.into(),
|
||||
build: value.build.map(Into::into),
|
||||
config: serde_json::Value::from_str(&value.config)?,
|
||||
tcp_connection: value.tcp_connection.map(Into::into),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<extension::DebugScenario> for DebugScenario {
|
||||
fn from(value: extension::DebugScenario) -> Self {
|
||||
Self {
|
||||
adapter: value.adapter.into(),
|
||||
label: value.label.into(),
|
||||
build: value.build.map(Into::into),
|
||||
config: value.config.to_string(),
|
||||
tcp_connection: value.tcp_connection.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpawnInTerminal> for ResolvedTask {
|
||||
fn from(value: SpawnInTerminal) -> Self {
|
||||
Self {
|
||||
label: value.label,
|
||||
command: value.command,
|
||||
args: value.args,
|
||||
env: value.env.into_iter().collect(),
|
||||
cwd: value.cwd.map(|s| s.to_string_lossy().into_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CodeLabel> for extension::CodeLabel {
|
||||
fn from(value: CodeLabel) -> Self {
|
||||
Self {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue