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
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4242,6 +4242,7 @@ dependencies = [
|
||||||
"gpui",
|
"gpui",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"task",
|
"task",
|
||||||
|
"util",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -368,7 +368,7 @@ pub trait DebugAdapter: 'static + Send + Sync {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dap_schema(&self) -> serde_json::Value;
|
fn dap_schema(&self) -> serde_json::Value;
|
||||||
|
|
||||||
fn label_for_child_session(&self, _args: &StartDebuggingRequestArguments) -> Option<String> {
|
fn label_for_child_session(&self, _args: &StartDebuggingRequestArguments) -> Option<String> {
|
||||||
None
|
None
|
||||||
|
@ -394,7 +394,7 @@ impl DebugAdapter for FakeAdapter {
|
||||||
DebugAdapterName(Self::ADAPTER_NAME.into())
|
DebugAdapterName(Self::ADAPTER_NAME.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dap_schema(&self) -> serde_json::Value {
|
fn dap_schema(&self) -> serde_json::Value {
|
||||||
serde_json::Value::Null
|
serde_json::Value::Null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
|
|
||||||
/// Given a user build configuration, locator creates a fill-in debug target ([DebugRequest]) on behalf of the user.
|
/// Given a user build configuration, locator creates a fill-in debug target ([DebugScenario]) on behalf of the user.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait DapLocator: Send + Sync {
|
pub trait DapLocator: Send + Sync {
|
||||||
fn name(&self) -> SharedString;
|
fn name(&self) -> SharedString;
|
||||||
|
@ -67,13 +67,12 @@ impl DapRegistry {
|
||||||
pub async fn adapters_schema(&self) -> task::AdapterSchemas {
|
pub async fn adapters_schema(&self) -> task::AdapterSchemas {
|
||||||
let mut schemas = AdapterSchemas(vec![]);
|
let mut schemas = AdapterSchemas(vec![]);
|
||||||
|
|
||||||
// Clone to avoid holding lock over await points
|
|
||||||
let adapters = self.0.read().adapters.clone();
|
let adapters = self.0.read().adapters.clone();
|
||||||
|
|
||||||
for (name, adapter) in adapters.into_iter() {
|
for (name, adapter) in adapters.into_iter() {
|
||||||
schemas.0.push(AdapterSchema {
|
schemas.0.push(AdapterSchema {
|
||||||
adapter: name.into(),
|
adapter: name.into(),
|
||||||
schema: adapter.dap_schema().await,
|
schema: adapter.dap_schema(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ impl DebugAdapter for CodeLldbDebugAdapter {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dap_schema(&self) -> serde_json::Value {
|
fn dap_schema(&self) -> serde_json::Value {
|
||||||
json!({
|
json!({
|
||||||
"properties": {
|
"properties": {
|
||||||
"request": {
|
"request": {
|
||||||
|
|
|
@ -63,7 +63,7 @@ impl DebugAdapter for GdbDebugAdapter {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dap_schema(&self) -> serde_json::Value {
|
fn dap_schema(&self) -> serde_json::Value {
|
||||||
json!({
|
json!({
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -95,7 +95,7 @@ impl DebugAdapter for GoDebugAdapter {
|
||||||
Some(SharedString::new_static("Go").into())
|
Some(SharedString::new_static("Go").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dap_schema(&self) -> serde_json::Value {
|
fn dap_schema(&self) -> serde_json::Value {
|
||||||
// Create common properties shared between launch and attach
|
// Create common properties shared between launch and attach
|
||||||
let common_properties = json!({
|
let common_properties = json!({
|
||||||
"debugAdapter": {
|
"debugAdapter": {
|
||||||
|
|
|
@ -182,7 +182,7 @@ impl DebugAdapter for JsDebugAdapter {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dap_schema(&self) -> serde_json::Value {
|
fn dap_schema(&self) -> serde_json::Value {
|
||||||
json!({
|
json!({
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -110,7 +110,7 @@ impl PhpDebugAdapter {
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl DebugAdapter for PhpDebugAdapter {
|
impl DebugAdapter for PhpDebugAdapter {
|
||||||
async fn dap_schema(&self) -> serde_json::Value {
|
fn dap_schema(&self) -> serde_json::Value {
|
||||||
json!({
|
json!({
|
||||||
"properties": {
|
"properties": {
|
||||||
"request": {
|
"request": {
|
||||||
|
|
|
@ -257,7 +257,7 @@ impl DebugAdapter for PythonDebugAdapter {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dap_schema(&self) -> serde_json::Value {
|
fn dap_schema(&self) -> serde_json::Value {
|
||||||
json!({
|
json!({
|
||||||
"properties": {
|
"properties": {
|
||||||
"request": {
|
"request": {
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl DebugAdapter for RubyDebugAdapter {
|
||||||
Ok(StartDebuggingRequestArgumentsRequest::Launch)
|
Ok(StartDebuggingRequestArgumentsRequest::Launch)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dap_schema(&self) -> serde_json::Value {
|
fn dap_schema(&self) -> serde_json::Value {
|
||||||
json!({
|
json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
@ -12,6 +12,7 @@ dap.workspace = true
|
||||||
extension.workspace = true
|
extension.workspace = true
|
||||||
gpui.workspace = true
|
gpui.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
util.workspace = true
|
||||||
task.workspace = true
|
task.workspace = true
|
||||||
workspace-hack = { version = "0.1", path = "../../tooling/workspace-hack" }
|
workspace-hack = { version = "0.1", path = "../../tooling/workspace-hack" }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
mod extension_dap_adapter;
|
mod extension_dap_adapter;
|
||||||
|
mod extension_locator_adapter;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -6,6 +7,9 @@ use dap::DapRegistry;
|
||||||
use extension::{ExtensionDebugAdapterProviderProxy, ExtensionHostProxy};
|
use extension::{ExtensionDebugAdapterProviderProxy, ExtensionHostProxy};
|
||||||
use extension_dap_adapter::ExtensionDapAdapter;
|
use extension_dap_adapter::ExtensionDapAdapter;
|
||||||
use gpui::App;
|
use gpui::App;
|
||||||
|
use util::ResultExt;
|
||||||
|
|
||||||
|
use crate::extension_locator_adapter::ExtensionLocatorAdapter;
|
||||||
|
|
||||||
pub fn init(extension_host_proxy: Arc<ExtensionHostProxy>, cx: &mut App) {
|
pub fn init(extension_host_proxy: Arc<ExtensionHostProxy>, cx: &mut App) {
|
||||||
let language_server_registry_proxy = DebugAdapterRegistryProxy::new(cx);
|
let language_server_registry_proxy = DebugAdapterRegistryProxy::new(cx);
|
||||||
|
@ -30,11 +34,21 @@ impl ExtensionDebugAdapterProviderProxy for DebugAdapterRegistryProxy {
|
||||||
&self,
|
&self,
|
||||||
extension: Arc<dyn extension::Extension>,
|
extension: Arc<dyn extension::Extension>,
|
||||||
debug_adapter_name: Arc<str>,
|
debug_adapter_name: Arc<str>,
|
||||||
|
) {
|
||||||
|
if let Some(adapter) = ExtensionDapAdapter::new(extension, debug_adapter_name).log_err() {
|
||||||
|
self.debug_adapter_registry.add_adapter(Arc::new(adapter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_debug_locator(
|
||||||
|
&self,
|
||||||
|
extension: Arc<dyn extension::Extension>,
|
||||||
|
locator_name: Arc<str>,
|
||||||
) {
|
) {
|
||||||
self.debug_adapter_registry
|
self.debug_adapter_registry
|
||||||
.add_adapter(Arc::new(ExtensionDapAdapter::new(
|
.add_locator(Arc::new(ExtensionLocatorAdapter::new(
|
||||||
extension,
|
extension,
|
||||||
debug_adapter_name,
|
locator_name,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
use std::{path::PathBuf, sync::Arc};
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
str::FromStr,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use dap::adapters::{
|
use dap::adapters::{
|
||||||
DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, DebugTaskDefinition,
|
DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, DebugTaskDefinition,
|
||||||
|
@ -12,17 +16,26 @@ use task::{DebugScenario, ZedDebugConfig};
|
||||||
pub(crate) struct ExtensionDapAdapter {
|
pub(crate) struct ExtensionDapAdapter {
|
||||||
extension: Arc<dyn Extension>,
|
extension: Arc<dyn Extension>,
|
||||||
debug_adapter_name: Arc<str>,
|
debug_adapter_name: Arc<str>,
|
||||||
|
schema: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtensionDapAdapter {
|
impl ExtensionDapAdapter {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
extension: Arc<dyn extension::Extension>,
|
extension: Arc<dyn extension::Extension>,
|
||||||
debug_adapter_name: Arc<str>,
|
debug_adapter_name: Arc<str>,
|
||||||
) -> Self {
|
) -> Result<Self> {
|
||||||
Self {
|
let schema = std::fs::read_to_string(extension.path_from_extension(
|
||||||
|
&Path::new("debug_adapter_schemas").join(debug_adapter_name.as_ref()),
|
||||||
|
))
|
||||||
|
.with_context(|| format!("Failed to read debug adapter schema for {debug_adapter_name}"))?;
|
||||||
|
let schema = serde_json::Value::from_str(&schema).with_context(|| {
|
||||||
|
format!("Debug adapter schema for {debug_adapter_name} is not a valid JSON")
|
||||||
|
})?;
|
||||||
|
Ok(Self {
|
||||||
extension,
|
extension,
|
||||||
debug_adapter_name,
|
debug_adapter_name,
|
||||||
}
|
schema,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +74,8 @@ impl DebugAdapter for ExtensionDapAdapter {
|
||||||
self.debug_adapter_name.as_ref().into()
|
self.debug_adapter_name.as_ref().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dap_schema(&self) -> serde_json::Value {
|
fn dap_schema(&self) -> serde_json::Value {
|
||||||
self.extension.get_dap_schema().await.unwrap_or_default()
|
self.schema.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_binary(
|
async fn get_binary(
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use dap::{DapLocator, DebugRequest, adapters::DebugAdapterName};
|
||||||
|
use extension::Extension;
|
||||||
|
use gpui::SharedString;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use task::{DebugScenario, SpawnInTerminal, TaskTemplate};
|
||||||
|
|
||||||
|
pub(crate) struct ExtensionLocatorAdapter {
|
||||||
|
extension: Arc<dyn Extension>,
|
||||||
|
locator_name: SharedString,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExtensionLocatorAdapter {
|
||||||
|
pub(crate) fn new(extension: Arc<dyn extension::Extension>, locator_name: Arc<str>) -> Self {
|
||||||
|
Self {
|
||||||
|
extension,
|
||||||
|
locator_name: SharedString::from(locator_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl DapLocator for ExtensionLocatorAdapter {
|
||||||
|
fn name(&self) -> SharedString {
|
||||||
|
self.locator_name.clone()
|
||||||
|
}
|
||||||
|
/// Determines whether this locator can generate debug target for given task.
|
||||||
|
async fn create_scenario(
|
||||||
|
&self,
|
||||||
|
build_config: &TaskTemplate,
|
||||||
|
resolved_label: &str,
|
||||||
|
adapter: &DebugAdapterName,
|
||||||
|
) -> Option<DebugScenario> {
|
||||||
|
self.extension
|
||||||
|
.dap_locator_create_scenario(
|
||||||
|
self.locator_name.as_ref().to_owned(),
|
||||||
|
build_config.clone(),
|
||||||
|
resolved_label.to_owned(),
|
||||||
|
adapter.0.as_ref().to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(&self, _build_config: SpawnInTerminal) -> Result<DebugRequest> {
|
||||||
|
Err(anyhow::anyhow!("Not implemented"))
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ use fs::normalize_path;
|
||||||
use gpui::{App, Task};
|
use gpui::{App, Task};
|
||||||
use language::LanguageName;
|
use language::LanguageName;
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
|
use task::{SpawnInTerminal, ZedDebugConfig};
|
||||||
|
|
||||||
pub use crate::extension_events::*;
|
pub use crate::extension_events::*;
|
||||||
pub use crate::extension_host_proxy::*;
|
pub use crate::extension_host_proxy::*;
|
||||||
|
@ -144,7 +145,30 @@ pub trait Extension: Send + Sync + 'static {
|
||||||
worktree: Arc<dyn WorktreeDelegate>,
|
worktree: Arc<dyn WorktreeDelegate>,
|
||||||
) -> Result<DebugAdapterBinary>;
|
) -> Result<DebugAdapterBinary>;
|
||||||
|
|
||||||
async fn get_dap_schema(&self) -> Result<serde_json::Value>;
|
async fn dap_request_kind(
|
||||||
|
&self,
|
||||||
|
dap_name: Arc<str>,
|
||||||
|
config: serde_json::Value,
|
||||||
|
) -> Result<StartDebuggingRequestArgumentsRequest>;
|
||||||
|
|
||||||
|
async fn dap_config_to_scenario(
|
||||||
|
&self,
|
||||||
|
config: ZedDebugConfig,
|
||||||
|
worktree: Arc<dyn WorktreeDelegate>,
|
||||||
|
) -> Result<DebugScenario>;
|
||||||
|
|
||||||
|
async fn dap_locator_create_scenario(
|
||||||
|
&self,
|
||||||
|
locator_name: String,
|
||||||
|
build_config_template: BuildTaskTemplate,
|
||||||
|
resolved_label: String,
|
||||||
|
debug_adapter_name: String,
|
||||||
|
) -> Result<Option<DebugScenario>>;
|
||||||
|
async fn run_dap_locator(
|
||||||
|
&self,
|
||||||
|
locator_name: String,
|
||||||
|
config: SpawnInTerminal,
|
||||||
|
) -> Result<DebugRequest>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_wasm_extension_version(
|
pub fn parse_wasm_extension_version(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ExtensionLibraryKind, ExtensionManifest, GrammarManifestEntry, parse_wasm_extension_version,
|
ExtensionLibraryKind, ExtensionManifest, GrammarManifestEntry, parse_wasm_extension_version,
|
||||||
};
|
};
|
||||||
use anyhow::{Context as _, Result, bail};
|
use anyhow::{Context as _, Result, bail, ensure};
|
||||||
use async_compression::futures::bufread::GzipDecoder;
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
use async_tar::Archive;
|
use async_tar::Archive;
|
||||||
use futures::io::BufReader;
|
use futures::io::BufReader;
|
||||||
|
@ -12,6 +12,7 @@ use std::{
|
||||||
env, fs, mem,
|
env, fs, mem,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Stdio,
|
process::Stdio,
|
||||||
|
str::FromStr,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use wasm_encoder::{ComponentSectionId, Encode as _, RawSection, Section as _};
|
use wasm_encoder::{ComponentSectionId, Encode as _, RawSection, Section as _};
|
||||||
|
@ -97,6 +98,23 @@ impl ExtensionBuilder {
|
||||||
log::info!("compiled Rust extension {}", extension_dir.display());
|
log::info!("compiled Rust extension {}", extension_dir.display());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let debug_adapters_dir = extension_dir.join("debug_adapter_schemas");
|
||||||
|
if !extension_manifest.debug_adapters.is_empty() {
|
||||||
|
ensure!(
|
||||||
|
debug_adapters_dir.exists(),
|
||||||
|
"Expected debug adapter schemas directory to exist"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for debug_adapter_name in &extension_manifest.debug_adapters {
|
||||||
|
let debug_adapter_schema_path = debug_adapters_dir.join(debug_adapter_name.as_ref());
|
||||||
|
let debug_adapter_schema = fs::read_to_string(&debug_adapter_schema_path)
|
||||||
|
.with_context(|| {
|
||||||
|
format!("failed to read debug adapter schema for `{debug_adapter_name}`")
|
||||||
|
})?;
|
||||||
|
_ = serde_json::Value::from_str(&debug_adapter_schema).with_context(|| {
|
||||||
|
format!("Debug adapter schema for `{debug_adapter_name}` is not a valid JSON")
|
||||||
|
})?;
|
||||||
|
}
|
||||||
for (grammar_name, grammar_metadata) in &extension_manifest.grammars {
|
for (grammar_name, grammar_metadata) in &extension_manifest.grammars {
|
||||||
let snake_cased_grammar_name = grammar_name.to_snake_case();
|
let snake_cased_grammar_name = grammar_name.to_snake_case();
|
||||||
if grammar_name.as_ref() != snake_cased_grammar_name.as_str() {
|
if grammar_name.as_ref() != snake_cased_grammar_name.as_str() {
|
||||||
|
|
|
@ -412,6 +412,7 @@ impl ExtensionIndexedDocsProviderProxy for ExtensionHostProxy {
|
||||||
|
|
||||||
pub trait ExtensionDebugAdapterProviderProxy: Send + Sync + 'static {
|
pub trait ExtensionDebugAdapterProviderProxy: Send + Sync + 'static {
|
||||||
fn register_debug_adapter(&self, extension: Arc<dyn Extension>, debug_adapter_name: Arc<str>);
|
fn register_debug_adapter(&self, extension: Arc<dyn Extension>, debug_adapter_name: Arc<str>);
|
||||||
|
fn register_debug_locator(&self, extension: Arc<dyn Extension>, locator_name: Arc<str>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtensionDebugAdapterProviderProxy for ExtensionHostProxy {
|
impl ExtensionDebugAdapterProviderProxy for ExtensionHostProxy {
|
||||||
|
@ -422,4 +423,12 @@ impl ExtensionDebugAdapterProviderProxy for ExtensionHostProxy {
|
||||||
|
|
||||||
proxy.register_debug_adapter(extension, debug_adapter_name)
|
proxy.register_debug_adapter(extension, debug_adapter_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_debug_locator(&self, extension: Arc<dyn Extension>, locator_name: Arc<str>) {
|
||||||
|
let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
proxy.register_debug_locator(extension, locator_name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,8 @@ pub struct ExtensionManifest {
|
||||||
pub capabilities: Vec<ExtensionCapability>,
|
pub capabilities: Vec<ExtensionCapability>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub debug_adapters: Vec<Arc<str>>,
|
pub debug_adapters: Vec<Arc<str>>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub debug_locators: Vec<Arc<str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtensionManifest {
|
impl ExtensionManifest {
|
||||||
|
@ -277,6 +279,7 @@ fn manifest_from_old_manifest(
|
||||||
snippets: None,
|
snippets: None,
|
||||||
capabilities: Vec::new(),
|
capabilities: Vec::new(),
|
||||||
debug_adapters: vec![],
|
debug_adapters: vec![],
|
||||||
|
debug_locators: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +308,7 @@ mod tests {
|
||||||
snippets: None,
|
snippets: None,
|
||||||
capabilities: vec![],
|
capabilities: vec![],
|
||||||
debug_adapters: Default::default(),
|
debug_adapters: Default::default(),
|
||||||
|
debug_locators: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,4 +2,7 @@ pub use dap::{
|
||||||
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
|
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
|
||||||
adapters::{DebugAdapterBinary, DebugTaskDefinition, TcpArguments},
|
adapters::{DebugAdapterBinary, DebugTaskDefinition, TcpArguments},
|
||||||
};
|
};
|
||||||
pub use task::{AttachRequest, DebugRequest, LaunchRequest, TcpArgumentsTemplate};
|
pub use task::{
|
||||||
|
AttachRequest, BuildTaskDefinition, DebugRequest, DebugScenario, LaunchRequest,
|
||||||
|
TaskTemplate as BuildTaskTemplate, TcpArgumentsTemplate,
|
||||||
|
};
|
||||||
|
|
|
@ -20,8 +20,8 @@ pub use wit::{
|
||||||
make_file_executable,
|
make_file_executable,
|
||||||
zed::extension::context_server::ContextServerConfiguration,
|
zed::extension::context_server::ContextServerConfiguration,
|
||||||
zed::extension::dap::{
|
zed::extension::dap::{
|
||||||
DebugAdapterBinary, DebugTaskDefinition, StartDebuggingRequestArguments,
|
DebugAdapterBinary, DebugRequest, DebugTaskDefinition, StartDebuggingRequestArguments,
|
||||||
StartDebuggingRequestArgumentsRequest, TcpArguments, TcpArgumentsTemplate,
|
StartDebuggingRequestArgumentsRequest, TaskTemplate, TcpArguments, TcpArgumentsTemplate,
|
||||||
resolve_tcp_template,
|
resolve_tcp_template,
|
||||||
},
|
},
|
||||||
zed::extension::github::{
|
zed::extension::github::{
|
||||||
|
@ -204,8 +204,35 @@ pub trait Extension: Send + Sync {
|
||||||
Err("`get_dap_binary` not implemented".to_string())
|
Err("`get_dap_binary` not implemented".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dap_schema(&mut self) -> Result<serde_json::Value, String> {
|
fn dap_request_kind(
|
||||||
Err("`dap_schema` not implemented".to_string())
|
&mut self,
|
||||||
|
_adapter_name: String,
|
||||||
|
_config: serde_json::Value,
|
||||||
|
) -> Result<StartDebuggingRequestArgumentsRequest, String> {
|
||||||
|
Err("`dap_request_kind` not implemented".to_string())
|
||||||
|
}
|
||||||
|
fn dap_config_to_scenario(
|
||||||
|
&mut self,
|
||||||
|
_adapter_name: DebugConfig,
|
||||||
|
_config: &Worktree,
|
||||||
|
) -> Result<DebugScenario, String> {
|
||||||
|
Err("`dap_config_to_scenario` not implemented".to_string())
|
||||||
|
}
|
||||||
|
fn dap_locator_create_scenario(
|
||||||
|
&mut self,
|
||||||
|
_locator_name: String,
|
||||||
|
_build_task: TaskTemplate,
|
||||||
|
_resolved_label: String,
|
||||||
|
_debug_adapter_name: String,
|
||||||
|
) -> Option<DebugScenario> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn run_dap_locator(
|
||||||
|
&mut self,
|
||||||
|
_locator_name: String,
|
||||||
|
_build_task: TaskTemplate,
|
||||||
|
) -> Result<DebugRequest, String> {
|
||||||
|
Err("`run_dap_locator` not implemented".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,8 +428,39 @@ impl wit::Guest for Component {
|
||||||
extension().get_dap_binary(adapter_name, config, user_installed_path, worktree)
|
extension().get_dap_binary(adapter_name, config, user_installed_path, worktree)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dap_schema() -> Result<String, String> {
|
fn dap_request_kind(
|
||||||
extension().dap_schema().map(|schema| schema.to_string())
|
adapter_name: String,
|
||||||
|
config: String,
|
||||||
|
) -> Result<StartDebuggingRequestArgumentsRequest, String> {
|
||||||
|
extension().dap_request_kind(
|
||||||
|
adapter_name,
|
||||||
|
serde_json::from_str(&config).map_err(|e| format!("Failed to parse config: {e}"))?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn dap_config_to_scenario(
|
||||||
|
config: DebugConfig,
|
||||||
|
worktree: &Worktree,
|
||||||
|
) -> Result<DebugScenario, String> {
|
||||||
|
extension().dap_config_to_scenario(config, worktree)
|
||||||
|
}
|
||||||
|
fn dap_locator_create_scenario(
|
||||||
|
locator_name: String,
|
||||||
|
build_task: TaskTemplate,
|
||||||
|
resolved_label: String,
|
||||||
|
debug_adapter_name: String,
|
||||||
|
) -> Option<DebugScenario> {
|
||||||
|
extension().dap_locator_create_scenario(
|
||||||
|
locator_name,
|
||||||
|
build_task,
|
||||||
|
resolved_label,
|
||||||
|
debug_adapter_name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn run_dap_locator(
|
||||||
|
locator_name: String,
|
||||||
|
build_task: TaskTemplate,
|
||||||
|
) -> Result<DebugRequest, String> {
|
||||||
|
extension().run_dap_locator(locator_name, build_task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,55 @@ interface dap {
|
||||||
timeout: option<u64>,
|
timeout: option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
record debug-task-definition {
|
/// Debug Config is the "highest-level" configuration for a debug session.
|
||||||
|
/// It comes from a new session modal UI; thus, it is essentially debug-adapter-agnostic.
|
||||||
|
/// It is expected of the extension to translate this generic configuration into something that can be debugged by the adapter (debug scenario).
|
||||||
|
record debug-config {
|
||||||
|
/// Name of the debug task
|
||||||
label: string,
|
label: string,
|
||||||
|
/// The debug adapter to use
|
||||||
adapter: string,
|
adapter: string,
|
||||||
|
request: debug-request,
|
||||||
|
stop-on-entry: option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
record task-template {
|
||||||
|
/// Human readable name of the task to display in the UI.
|
||||||
|
label: string,
|
||||||
|
/// Executable command to spawn.
|
||||||
|
command: string,
|
||||||
|
args: list<string>,
|
||||||
|
env: env-vars,
|
||||||
|
cwd: option<string>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A task template with substituted task variables.
|
||||||
|
type resolved-task = task-template;
|
||||||
|
|
||||||
|
/// A task template for building a debug target.
|
||||||
|
type build-task-template = task-template;
|
||||||
|
|
||||||
|
variant build-task-definition {
|
||||||
|
by-name(string),
|
||||||
|
template(build-task-definition-template-payload )
|
||||||
|
}
|
||||||
|
record build-task-definition-template-payload {
|
||||||
|
locator-name: option<string>,
|
||||||
|
template: build-task-template
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Debug Scenario is the user-facing configuration type (used in debug.json). It is still concerned with what to debug and not necessarily how to do it (except for any
|
||||||
|
/// debug-adapter-specific configuration options).
|
||||||
|
record debug-scenario {
|
||||||
|
/// Unsubstituted label for the task.DebugAdapterBinary
|
||||||
|
label: string,
|
||||||
|
/// Name of the Debug Adapter this configuration is intended for.
|
||||||
|
adapter: string,
|
||||||
|
/// An optional build step to be ran prior to starting a debug session. Build steps are used by Zed's locators to locate the executable to debug.
|
||||||
|
build: option<build-task-definition>,
|
||||||
|
/// JSON-encoded configuration for a given debug adapter.
|
||||||
config: string,
|
config: string,
|
||||||
|
/// TCP connection parameters (if they were specified by user)
|
||||||
tcp-connection: option<tcp-arguments-template>,
|
tcp-connection: option<tcp-arguments-template>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,16 +89,34 @@ interface dap {
|
||||||
attach,
|
attach,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record debug-task-definition {
|
||||||
|
/// Unsubstituted label for the task.DebugAdapterBinary
|
||||||
|
label: string,
|
||||||
|
/// Name of the Debug Adapter this configuration is intended for.
|
||||||
|
adapter: string,
|
||||||
|
/// JSON-encoded configuration for a given debug adapter.
|
||||||
|
config: string,
|
||||||
|
/// TCP connection parameters (if they were specified by user)
|
||||||
|
tcp-connection: option<tcp-arguments-template>,
|
||||||
|
}
|
||||||
|
|
||||||
record start-debugging-request-arguments {
|
record start-debugging-request-arguments {
|
||||||
|
/// JSON-encoded configuration for a given debug adapter. It is specific to each debug adapter.
|
||||||
|
/// `configuration` will have it's Zed variable references substituted prior to being passed to the debug adapter.
|
||||||
configuration: string,
|
configuration: string,
|
||||||
request: start-debugging-request-arguments-request,
|
request: start-debugging-request-arguments-request,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The lowest-level representation of a debug session, which specifies:
|
||||||
|
/// - How to start a debug adapter process
|
||||||
|
/// - How to start a debug session with it (using DAP protocol)
|
||||||
|
/// for a given debug scenario.
|
||||||
record debug-adapter-binary {
|
record debug-adapter-binary {
|
||||||
command: option<string>,
|
command: option<string>,
|
||||||
arguments: list<string>,
|
arguments: list<string>,
|
||||||
envs: env-vars,
|
envs: env-vars,
|
||||||
cwd: option<string>,
|
cwd: option<string>,
|
||||||
|
/// Zed will use TCP transport if `connection` is specified.
|
||||||
connection: option<tcp-arguments>,
|
connection: option<tcp-arguments>,
|
||||||
request-args: start-debugging-request-arguments
|
request-args: start-debugging-request-arguments
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ world extension {
|
||||||
|
|
||||||
use common.{env-vars, range};
|
use common.{env-vars, range};
|
||||||
use context-server.{context-server-configuration};
|
use context-server.{context-server-configuration};
|
||||||
use dap.{debug-adapter-binary, debug-task-definition, debug-request};
|
use dap.{attach-request, build-task-template, debug-config, debug-adapter-binary, debug-task-definition, debug-request, debug-scenario, launch-request, resolved-task, start-debugging-request-arguments-request};
|
||||||
use lsp.{completion, symbol};
|
use lsp.{completion, symbol};
|
||||||
use process.{command};
|
use process.{command};
|
||||||
use slash-command.{slash-command, slash-command-argument-completion, slash-command-output};
|
use slash-command.{slash-command, slash-command-argument-completion, slash-command-output};
|
||||||
|
@ -159,6 +159,9 @@ world extension {
|
||||||
|
|
||||||
/// Returns a configured debug adapter binary for a given debug task.
|
/// Returns a configured debug adapter binary for a given debug task.
|
||||||
export get-dap-binary: func(adapter-name: string, config: debug-task-definition, user-installed-path: option<string>, worktree: borrow<worktree>) -> result<debug-adapter-binary, string>;
|
export get-dap-binary: func(adapter-name: string, config: debug-task-definition, user-installed-path: option<string>, worktree: borrow<worktree>) -> result<debug-adapter-binary, string>;
|
||||||
/// Get a debug adapter's configuration schema
|
/// Returns the kind of a debug scenario (launch or attach).
|
||||||
export dap-schema: func() -> result<string, string>;
|
export dap-request-kind: func(adapter-name: string, config: string) -> result<start-debugging-request-arguments-request, string>;
|
||||||
|
export dap-config-to-scenario: func(config: debug-config, worktree: borrow<worktree>) -> result<debug-scenario, string>;
|
||||||
|
export dap-locator-create-scenario: func(locator-name: string, build-config-template: build-task-template, resolved-label: string, debug-adapter-name: string) -> option<debug-scenario>;
|
||||||
|
export run-dap-locator: func(locator-name: string, config: resolved-task) -> result<debug-request, string>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,6 +139,7 @@ fn manifest() -> ExtensionManifest {
|
||||||
args: vec!["hello!".into()],
|
args: vec!["hello!".into()],
|
||||||
}],
|
}],
|
||||||
debug_adapters: Default::default(),
|
debug_adapters: Default::default(),
|
||||||
|
debug_locators: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1348,6 +1348,11 @@ impl ExtensionStore {
|
||||||
this.proxy
|
this.proxy
|
||||||
.register_debug_adapter(extension.clone(), debug_adapter.clone());
|
.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);
|
this.wasm_extensions.extend(wasm_extensions);
|
||||||
|
|
|
@ -163,6 +163,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
|
||||||
snippets: None,
|
snippets: None,
|
||||||
capabilities: Vec::new(),
|
capabilities: Vec::new(),
|
||||||
debug_adapters: Default::default(),
|
debug_adapters: Default::default(),
|
||||||
|
debug_locators: Default::default(),
|
||||||
}),
|
}),
|
||||||
dev: false,
|
dev: false,
|
||||||
},
|
},
|
||||||
|
@ -193,6 +194,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
|
||||||
snippets: None,
|
snippets: None,
|
||||||
capabilities: Vec::new(),
|
capabilities: Vec::new(),
|
||||||
debug_adapters: Default::default(),
|
debug_adapters: Default::default(),
|
||||||
|
debug_locators: Default::default(),
|
||||||
}),
|
}),
|
||||||
dev: false,
|
dev: false,
|
||||||
},
|
},
|
||||||
|
@ -368,6 +370,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
|
||||||
snippets: None,
|
snippets: None,
|
||||||
capabilities: Vec::new(),
|
capabilities: Vec::new(),
|
||||||
debug_adapters: Default::default(),
|
debug_adapters: Default::default(),
|
||||||
|
debug_locators: Default::default(),
|
||||||
}),
|
}),
|
||||||
dev: false,
|
dev: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,7 @@ pub mod wit;
|
||||||
use crate::ExtensionManifest;
|
use crate::ExtensionManifest;
|
||||||
use anyhow::{Context as _, Result, anyhow, bail};
|
use anyhow::{Context as _, Result, anyhow, bail};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use dap::{DebugRequest, StartDebuggingRequestArgumentsRequest};
|
||||||
use extension::{
|
use extension::{
|
||||||
CodeLabel, Command, Completion, ContextServerConfiguration, DebugAdapterBinary,
|
CodeLabel, Command, Completion, ContextServerConfiguration, DebugAdapterBinary,
|
||||||
DebugTaskDefinition, ExtensionHostProxy, KeyValueStoreDelegate, ProjectDelegate, SlashCommand,
|
DebugTaskDefinition, ExtensionHostProxy, KeyValueStoreDelegate, ProjectDelegate, SlashCommand,
|
||||||
|
@ -32,6 +33,7 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
use task::{DebugScenario, SpawnInTerminal, TaskTemplate, ZedDebugConfig};
|
||||||
use wasmtime::{
|
use wasmtime::{
|
||||||
CacheStore, Engine, Store,
|
CacheStore, Engine, Store,
|
||||||
component::{Component, ResourceTable},
|
component::{Component, ResourceTable},
|
||||||
|
@ -399,14 +401,76 @@ impl extension::Extension for WasmExtension {
|
||||||
})
|
})
|
||||||
.await
|
.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| {
|
self.call(|extension, store| {
|
||||||
async move {
|
async move {
|
||||||
extension
|
extension
|
||||||
.call_dap_schema(store)
|
.call_dap_locator_create_scenario(
|
||||||
|
store,
|
||||||
|
locator_name,
|
||||||
|
build_config_template,
|
||||||
|
resolved_label,
|
||||||
|
debug_adapter_name,
|
||||||
|
)
|
||||||
.await
|
.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))
|
.map_err(|err| store.data().extension_error(err))
|
||||||
}
|
}
|
||||||
.boxed()
|
.boxed()
|
||||||
|
|
|
@ -7,10 +7,14 @@ mod since_v0_3_0;
|
||||||
mod since_v0_4_0;
|
mod since_v0_4_0;
|
||||||
mod since_v0_5_0;
|
mod since_v0_5_0;
|
||||||
mod since_v0_6_0;
|
mod since_v0_6_0;
|
||||||
|
use dap::DebugRequest;
|
||||||
use extension::{DebugTaskDefinition, KeyValueStoreDelegate, WorktreeDelegate};
|
use extension::{DebugTaskDefinition, KeyValueStoreDelegate, WorktreeDelegate};
|
||||||
use language::LanguageName;
|
use language::LanguageName;
|
||||||
use lsp::LanguageServerName;
|
use lsp::LanguageServerName;
|
||||||
use release_channel::ReleaseChannel;
|
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 super::{WasmState, wasm_engine};
|
||||||
use anyhow::{Context as _, Result, anyhow};
|
use anyhow::{Context as _, Result, anyhow};
|
||||||
|
@ -922,18 +926,88 @@ impl Extension {
|
||||||
_ => anyhow::bail!("`get_dap_binary` not available prior to v0.6.0"),
|
_ => anyhow::bail!("`get_dap_binary` not available prior to v0.6.0"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub async fn call_dap_request_kind(
|
||||||
pub async fn call_dap_schema(&self, store: &mut Store<WasmState>) -> Result<String, String> {
|
&self,
|
||||||
|
store: &mut Store<WasmState>,
|
||||||
|
adapter_name: Arc<str>,
|
||||||
|
config: serde_json::Value,
|
||||||
|
) -> Result<Result<StartDebuggingRequestArgumentsRequest, String>> {
|
||||||
match self {
|
match self {
|
||||||
Extension::V0_6_0(ext) => {
|
Extension::V0_6_0(ext) => {
|
||||||
let schema = ext
|
let config =
|
||||||
.call_dap_schema(store)
|
serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
|
||||||
.await
|
let dap_binary = ext
|
||||||
.map_err(|err| err.to_string())?;
|
.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::{
|
use crate::wasm_host::wit::since_v0_6_0::{
|
||||||
dap::{
|
dap::{
|
||||||
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest, TcpArguments,
|
AttachRequest, BuildTaskDefinition, BuildTaskDefinitionTemplatePayload, LaunchRequest,
|
||||||
TcpArgumentsTemplate,
|
StartDebuggingRequestArguments, TcpArguments, TcpArgumentsTemplate,
|
||||||
},
|
},
|
||||||
slash_command::SlashCommandOutputSection,
|
slash_command::SlashCommandOutputSection,
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,7 @@ use extension::{
|
||||||
};
|
};
|
||||||
use futures::{AsyncReadExt, lock::Mutex};
|
use futures::{AsyncReadExt, lock::Mutex};
|
||||||
use futures::{FutureExt as _, io::BufReader};
|
use futures::{FutureExt as _, io::BufReader};
|
||||||
|
use gpui::SharedString;
|
||||||
use language::{BinaryStatus, LanguageName, language_settings::AllLanguageSettings};
|
use language::{BinaryStatus, LanguageName, language_settings::AllLanguageSettings};
|
||||||
use project::project_settings::ProjectSettings;
|
use project::project_settings::ProjectSettings;
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
|
@ -25,8 +26,10 @@ use std::{
|
||||||
env,
|
env,
|
||||||
net::Ipv4Addr,
|
net::Ipv4Addr,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
str::FromStr,
|
||||||
sync::{Arc, OnceLock},
|
sync::{Arc, OnceLock},
|
||||||
};
|
};
|
||||||
|
use task::{SpawnInTerminal, ZedDebugConfig};
|
||||||
use util::{archive::extract_zip, maybe};
|
use util::{archive::extract_zip, maybe};
|
||||||
use wasmtime::component::{Linker, Resource};
|
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 {
|
impl TryFrom<extension::DebugTaskDefinition> for DebugTaskDefinition {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
fn try_from(value: extension::DebugTaskDefinition) -> Result<Self, Self::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 {
|
impl TryFrom<DebugAdapterBinary> for extension::DebugAdapterBinary {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
fn try_from(value: DebugAdapterBinary) -> Result<Self, Self::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 {
|
impl From<CodeLabel> for extension::CodeLabel {
|
||||||
fn from(value: CodeLabel) -> Self {
|
fn from(value: CodeLabel) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue