Add a JS/TS debug locator (#31769)
With this, a semi-working debug session is possible from the JS/TS gutter tasks: https://github.com/user-attachments/assets/8db6ed29-b44a-4314-ae8b-a8213291bffc For now, available in debug builds only as a base to improve on later on the DAP front. Release Notes: - N/A --------- Co-authored-by: Piotr Osiewicz <peterosiewicz@gmail.com>
This commit is contained in:
parent
0ee900e8fb
commit
1e83022f03
8 changed files with 95 additions and 13 deletions
|
@ -298,6 +298,7 @@ pub async fn download_adapter_from_github(
|
|||
response.status().to_string()
|
||||
);
|
||||
|
||||
delegate.output_to_console("Download complete".to_owned());
|
||||
match file_type {
|
||||
DownloadedFileType::GzipTar => {
|
||||
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
|
||||
|
|
|
@ -434,7 +434,7 @@ impl TransportDelegate {
|
|||
.with_context(|| "reading a message from server")?
|
||||
== 0
|
||||
{
|
||||
anyhow::bail!("debugger reader stream closed");
|
||||
anyhow::bail!("debugger reader stream closed, last string output: '{buffer}'");
|
||||
};
|
||||
|
||||
if buffer == "\r\n" {
|
||||
|
|
|
@ -26,7 +26,7 @@ impl JsDebugAdapter {
|
|||
delegate: &Arc<dyn DapDelegate>,
|
||||
) -> Result<AdapterVersion> {
|
||||
let release = latest_github_release(
|
||||
&format!("{}/{}", "microsoft", Self::ADAPTER_NPM_NAME),
|
||||
&format!("microsoft/{}", Self::ADAPTER_NPM_NAME),
|
||||
true,
|
||||
false,
|
||||
delegate.http_client(),
|
||||
|
@ -449,6 +449,8 @@ impl DebugAdapter for JsDebugAdapter {
|
|||
delegate.as_ref(),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
delegate.output_to_console(format!("{} debug adapter is up to date", self.name()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -168,8 +168,9 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
command: TYPESCRIPT_RUNNER_VARIABLE.template_value(),
|
||||
args: vec![
|
||||
TYPESCRIPT_JEST_TASK_VARIABLE.template_value(),
|
||||
VariableName::File.template_value(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
task_templates.0.push(TaskTemplate {
|
||||
|
@ -183,13 +184,14 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
TYPESCRIPT_JEST_TASK_VARIABLE.template_value(),
|
||||
"--testNamePattern".to_owned(),
|
||||
format!("\"{}\"", VariableName::Symbol.template_value()),
|
||||
VariableName::File.template_value(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
tags: vec![
|
||||
"ts-test".to_owned(),
|
||||
"js-test".to_owned(),
|
||||
"tsx-test".to_owned(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
|
||||
|
@ -203,8 +205,9 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
args: vec![
|
||||
TYPESCRIPT_VITEST_TASK_VARIABLE.template_value(),
|
||||
"run".to_owned(),
|
||||
VariableName::File.template_value(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
task_templates.0.push(TaskTemplate {
|
||||
|
@ -219,13 +222,14 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
"run".to_owned(),
|
||||
"--testNamePattern".to_owned(),
|
||||
format!("\"{}\"", VariableName::Symbol.template_value()),
|
||||
VariableName::File.template_value(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
tags: vec![
|
||||
"ts-test".to_owned(),
|
||||
"js-test".to_owned(),
|
||||
"tsx-test".to_owned(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
|
||||
|
@ -238,8 +242,9 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
command: TYPESCRIPT_RUNNER_VARIABLE.template_value(),
|
||||
args: vec![
|
||||
TYPESCRIPT_MOCHA_TASK_VARIABLE.template_value(),
|
||||
VariableName::File.template_value(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
task_templates.0.push(TaskTemplate {
|
||||
|
@ -253,13 +258,14 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
TYPESCRIPT_MOCHA_TASK_VARIABLE.template_value(),
|
||||
"--grep".to_owned(),
|
||||
format!("\"{}\"", VariableName::Symbol.template_value()),
|
||||
VariableName::File.template_value(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
tags: vec![
|
||||
"ts-test".to_owned(),
|
||||
"js-test".to_owned(),
|
||||
"tsx-test".to_owned(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
|
||||
|
@ -272,8 +278,9 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
command: TYPESCRIPT_RUNNER_VARIABLE.template_value(),
|
||||
args: vec![
|
||||
TYPESCRIPT_JASMINE_TASK_VARIABLE.template_value(),
|
||||
VariableName::File.template_value(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
task_templates.0.push(TaskTemplate {
|
||||
|
@ -286,13 +293,14 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
args: vec![
|
||||
TYPESCRIPT_JASMINE_TASK_VARIABLE.template_value(),
|
||||
format!("--filter={}", VariableName::Symbol.template_value()),
|
||||
VariableName::File.template_value(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
tags: vec![
|
||||
"ts-test".to_owned(),
|
||||
"js-test".to_owned(),
|
||||
"tsx-test".to_owned(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
|
||||
|
@ -313,6 +321,7 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
package_json_script.template_value(),
|
||||
],
|
||||
tags: vec!["package-script".into()],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
}
|
||||
|
|
|
@ -103,8 +103,9 @@ impl DapStore {
|
|||
ADD_LOCATORS.call_once(|| {
|
||||
let registry = DapRegistry::global(cx);
|
||||
registry.add_locator(Arc::new(locators::cargo::CargoLocator {}));
|
||||
registry.add_locator(Arc::new(locators::python::PythonLocator));
|
||||
registry.add_locator(Arc::new(locators::go::GoLocator {}));
|
||||
registry.add_locator(Arc::new(locators::node::NodeLocator));
|
||||
registry.add_locator(Arc::new(locators::python::PythonLocator));
|
||||
});
|
||||
client.add_entity_request_handler(Self::handle_run_debug_locator);
|
||||
client.add_entity_request_handler(Self::handle_get_debug_adapter_binary);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub(crate) mod cargo;
|
||||
pub(crate) mod go;
|
||||
pub(crate) mod node;
|
||||
pub(crate) mod python;
|
||||
|
|
68
crates/project/src/debugger/locators/node.rs
Normal file
68
crates/project/src/debugger/locators/node.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use std::{borrow::Cow, path::Path};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use async_trait::async_trait;
|
||||
use dap::{DapLocator, DebugRequest, adapters::DebugAdapterName};
|
||||
use gpui::SharedString;
|
||||
|
||||
use task::{DebugScenario, SpawnInTerminal, TaskTemplate, VariableName};
|
||||
|
||||
pub(crate) struct NodeLocator;
|
||||
|
||||
const TYPESCRIPT_RUNNER_VARIABLE: VariableName =
|
||||
VariableName::Custom(Cow::Borrowed("TYPESCRIPT_RUNNER"));
|
||||
|
||||
#[async_trait]
|
||||
impl DapLocator for NodeLocator {
|
||||
fn name(&self) -> SharedString {
|
||||
SharedString::new_static("Node")
|
||||
}
|
||||
|
||||
/// Determines whether this locator can generate debug target for given task.
|
||||
fn create_scenario(
|
||||
&self,
|
||||
build_config: &TaskTemplate,
|
||||
resolved_label: &str,
|
||||
adapter: DebugAdapterName,
|
||||
) -> Option<DebugScenario> {
|
||||
// TODO(debugger) fix issues with `await` breakpoint step
|
||||
if cfg!(not(debug_assertions)) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if adapter.as_ref() != "JavaScript" {
|
||||
return None;
|
||||
}
|
||||
if build_config.command != TYPESCRIPT_RUNNER_VARIABLE.template_value() {
|
||||
return None;
|
||||
}
|
||||
let test_library = build_config.args.first()?;
|
||||
let program_path = Path::new("$ZED_WORKTREE_ROOT")
|
||||
.join("node_modules")
|
||||
.join(".bin")
|
||||
.join(test_library);
|
||||
let args = build_config.args[1..].to_vec();
|
||||
|
||||
let config = serde_json::json!({
|
||||
"request": "launch",
|
||||
"type": "pwa-node",
|
||||
"program": program_path,
|
||||
"args": args,
|
||||
"cwd": build_config.cwd.clone(),
|
||||
"runtimeArgs": ["--inspect-brk"],
|
||||
"console": "integratedTerminal",
|
||||
});
|
||||
|
||||
Some(DebugScenario {
|
||||
adapter: adapter.0,
|
||||
label: resolved_label.to_string().into(),
|
||||
build: None,
|
||||
config,
|
||||
tcp_connection: None,
|
||||
})
|
||||
}
|
||||
|
||||
async fn run(&self, _: SpawnInTerminal) -> Result<DebugRequest> {
|
||||
bail!("Python locator should not require DapLocator::run to be ran");
|
||||
}
|
||||
}
|
|
@ -1421,7 +1421,7 @@ impl Session {
|
|||
));
|
||||
return cx.spawn(async move |this, cx| {
|
||||
this.update(cx, |this, cx| process_result(this, error, cx))
|
||||
.log_err()
|
||||
.ok()
|
||||
.flatten()
|
||||
});
|
||||
}
|
||||
|
@ -1430,7 +1430,7 @@ impl Session {
|
|||
cx.spawn(async move |this, cx| {
|
||||
let result = request.await;
|
||||
this.update(cx, |this, cx| process_result(this, result, cx))
|
||||
.log_err()
|
||||
.ok()
|
||||
.flatten()
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue