debugger: Update docs with more examples (#31597)
This PR also shows more completion items when defining a debug config in a `debug.json` file. Mainly when using a pre build task argument. ### Follow ups - Add docs for Go, JS, PHP - Add attach docs Release Notes: - debugger beta: Show build task completions when editing a debug.json configuration with a pre build task - debugger beta: Add Python and Native Code debug config [examples](https://zed.dev/docs/debugger)
This commit is contained in:
parent
a387bf5f54
commit
804de3316e
5 changed files with 310 additions and 22 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -15588,6 +15588,7 @@ dependencies = [
|
|||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"hex",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"pretty_assertions",
|
||||
"proto",
|
||||
|
|
|
@ -660,7 +660,7 @@ impl DebugAdapter for PythonDebugAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
self.get_installed_binary(delegate, &config, None, None, false)
|
||||
self.get_installed_binary(delegate, &config, None, toolchain, false)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ collections.workspace = true
|
|||
futures.workspace = true
|
||||
gpui.workspace = true
|
||||
hex.workspace = true
|
||||
log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
proto.workspace = true
|
||||
schemars.workspace = true
|
||||
|
@ -29,8 +30,8 @@ serde_json_lenient.workspace = true
|
|||
sha2.workspace = true
|
||||
shellexpand.workspace = true
|
||||
util.workspace = true
|
||||
zed_actions.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
zed_actions.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use anyhow::{Context as _, Result};
|
||||
use collections::FxHashMap;
|
||||
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;
|
||||
|
||||
use crate::{TaskTemplate, adapter_schema::AdapterSchemas};
|
||||
|
||||
|
@ -182,7 +184,7 @@ impl From<AttachRequest> for DebugRequest {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
|
||||
#[derive(Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
|
||||
#[serde(untagged)]
|
||||
pub enum BuildTaskDefinition {
|
||||
ByName(SharedString),
|
||||
|
@ -194,6 +196,47 @@ pub enum BuildTaskDefinition {
|
|||
},
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for BuildTaskDefinition {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct TemplateHelper {
|
||||
#[serde(default)]
|
||||
label: Option<String>,
|
||||
#[serde(flatten)]
|
||||
rest: serde_json::Value,
|
||||
}
|
||||
|
||||
let value = serde_json::Value::deserialize(deserializer)?;
|
||||
|
||||
if let Ok(name) = serde_json::from_value::<SharedString>(value.clone()) {
|
||||
return Ok(BuildTaskDefinition::ByName(name));
|
||||
}
|
||||
|
||||
let helper: TemplateHelper =
|
||||
serde_json::from_value(value).map_err(serde::de::Error::custom)?;
|
||||
|
||||
let mut template_value = helper.rest;
|
||||
if let serde_json::Value::Object(ref mut map) = template_value {
|
||||
map.insert(
|
||||
"label".to_string(),
|
||||
serde_json::to_value(helper.label.unwrap_or_else(|| "debug-build".to_owned()))
|
||||
.map_err(serde::de::Error::custom)?,
|
||||
);
|
||||
}
|
||||
|
||||
let task_template: TaskTemplate =
|
||||
serde_json::from_value(template_value).map_err(serde::de::Error::custom)?;
|
||||
|
||||
Ok(BuildTaskDefinition::Template {
|
||||
task_template,
|
||||
locator_name: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, PartialEq, Eq, Clone, Debug, JsonSchema)]
|
||||
pub enum Request {
|
||||
Launch,
|
||||
|
@ -243,9 +286,96 @@ pub struct DebugScenario {
|
|||
pub struct DebugTaskFile(pub Vec<DebugScenario>);
|
||||
|
||||
impl DebugTaskFile {
|
||||
/// Generates JSON schema of Tasks JSON template format.
|
||||
pub fn generate_json_schema(schemas: &AdapterSchemas) -> serde_json_lenient::Value {
|
||||
schemas.generate_json_schema().unwrap_or_default()
|
||||
let build_task_schema = schemars::schema_for!(BuildTaskDefinition);
|
||||
let mut build_task_value =
|
||||
serde_json_lenient::to_value(&build_task_schema).unwrap_or_default();
|
||||
|
||||
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())
|
||||
{
|
||||
properties.remove("label");
|
||||
}
|
||||
|
||||
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!("Task Template schema in debug scenario's needs to be updated");
|
||||
}
|
||||
|
||||
let task_definitions = build_task_value
|
||||
.get("definitions")
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
|
||||
let adapter_conditions = schemas
|
||||
.0
|
||||
.iter()
|
||||
.map(|adapter_schema| {
|
||||
let adapter_name = adapter_schema.adapter.to_string();
|
||||
serde_json::json!({
|
||||
"if": {
|
||||
"properties": {
|
||||
"adapter": { "const": adapter_name }
|
||||
}
|
||||
},
|
||||
"then": adapter_schema.schema
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
serde_json_lenient::json!({
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Debug Configurations",
|
||||
"description": "Configuration for debug scenarios",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["adapter", "label"],
|
||||
"properties": {
|
||||
"adapter": {
|
||||
"type": "string",
|
||||
"description": "The name of the debug adapter"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "The name of the debug configuration"
|
||||
},
|
||||
"build": build_task_value,
|
||||
"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)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": adapter_conditions
|
||||
},
|
||||
"definitions": task_definitions
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,6 +384,32 @@ mod tests {
|
|||
use crate::DebugScenario;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn test_just_build_args() {
|
||||
let json = r#"{
|
||||
"label": "Build & debug rust",
|
||||
"adapter": "CodeLLDB",
|
||||
"build": {
|
||||
"command": "rust",
|
||||
"args": ["build"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
let deserialized: DebugScenario = serde_json::from_str(json).unwrap();
|
||||
assert!(deserialized.build.is_some());
|
||||
match deserialized.build.as_ref().unwrap() {
|
||||
crate::BuildTaskDefinition::Template { task_template, .. } => {
|
||||
assert_eq!("debug-build", task_template.label);
|
||||
assert_eq!("rust", task_template.command);
|
||||
assert_eq!(vec!["build"], task_template.args);
|
||||
}
|
||||
_ => panic!("Expected Template variant"),
|
||||
}
|
||||
assert_eq!(json!({}), deserialized.config);
|
||||
assert_eq!("CodeLLDB", deserialized.adapter.as_ref());
|
||||
assert_eq!("Build & debug rust", deserialized.label.as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_scenario_has_none_request() {
|
||||
let json = r#"{
|
||||
|
@ -307,4 +463,45 @@ mod tests {
|
|||
assert_eq!("CodeLLDB", deserialized.adapter.as_ref());
|
||||
assert_eq!("Attach to process", deserialized.label.as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_task_definition_without_label() {
|
||||
use crate::BuildTaskDefinition;
|
||||
|
||||
let json = r#""my_build_task""#;
|
||||
let deserialized: BuildTaskDefinition = serde_json::from_str(json).unwrap();
|
||||
match deserialized {
|
||||
BuildTaskDefinition::ByName(name) => assert_eq!("my_build_task", name.as_ref()),
|
||||
_ => panic!("Expected ByName variant"),
|
||||
}
|
||||
|
||||
let json = r#"{
|
||||
"command": "cargo",
|
||||
"args": ["build", "--release"]
|
||||
}"#;
|
||||
let deserialized: BuildTaskDefinition = serde_json::from_str(json).unwrap();
|
||||
match deserialized {
|
||||
BuildTaskDefinition::Template { task_template, .. } => {
|
||||
assert_eq!("debug-build", task_template.label);
|
||||
assert_eq!("cargo", task_template.command);
|
||||
assert_eq!(vec!["build", "--release"], task_template.args);
|
||||
}
|
||||
_ => panic!("Expected Template variant"),
|
||||
}
|
||||
|
||||
let json = r#"{
|
||||
"label": "Build Release",
|
||||
"command": "cargo",
|
||||
"args": ["build", "--release"]
|
||||
}"#;
|
||||
let deserialized: BuildTaskDefinition = serde_json::from_str(json).unwrap();
|
||||
match deserialized {
|
||||
BuildTaskDefinition::Template { task_template, .. } => {
|
||||
assert_eq!("Build Release", task_template.label);
|
||||
assert_eq!("cargo", task_template.command);
|
||||
assert_eq!(vec!["build", "--release"], task_template.args);
|
||||
}
|
||||
_ => panic!("Expected Template variant"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,15 +28,15 @@ These adapters enable Zed to provide a consistent debugging experience across mu
|
|||
|
||||
## Getting Started
|
||||
|
||||
For basic debugging you can set up a new configuration by opening the `New Session Modal` either via the `debugger: start` (default: f4) or clicking the plus icon at the top right of the debug panel.
|
||||
For basic debugging, you can set up a new configuration by opening the `New Session Modal` either via the `debugger: start` (default: f4) or by clicking the plus icon at the top right of the debug panel.
|
||||
|
||||
For more advanced use cases you can create debug configurations by directly editing the `.zed/debug.json` file in your project root directory.
|
||||
For more advanced use cases, you can create debug configurations by directly editing the `.zed/debug.json` file in your project root directory.
|
||||
|
||||
You can then use the `New Session Modal` to select a configuration then start debugging.
|
||||
You can then use the `New Session Modal` to select a configuration and start debugging.
|
||||
|
||||
### Configuration
|
||||
|
||||
While configuration fields are debug adapter dependent, most adapters support the following fields.
|
||||
While configuration fields are debug adapter-dependent, most adapters support the following fields:
|
||||
|
||||
```json
|
||||
[
|
||||
|
@ -58,22 +58,114 @@ While configuration fields are debug adapter dependent, most adapters support th
|
|||
]
|
||||
```
|
||||
|
||||
#### Task Variables
|
||||
#### Tasks
|
||||
|
||||
All configuration fields support task variables. See [Tasks](./tasks.md)
|
||||
All configuration fields support task variables. See [Tasks Variables](./tasks.md#variables)
|
||||
|
||||
Zed also allows embedding a task that is run before the debugger starts. This is useful for setting up the environment or running any necessary setup steps before the debugger starts.
|
||||
|
||||
See an example [here](#build-binary-then-debug)
|
||||
|
||||
#### Python Examples
|
||||
|
||||
##### Python Active File
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"label": "Active File",
|
||||
"adapter": "Debugpy",
|
||||
"program": "$ZED_FILE",
|
||||
"request": "launch"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
##### Flask App
|
||||
|
||||
For a common Flask Application with a file structure similar to the following:
|
||||
|
||||
- .venv/
|
||||
- app/
|
||||
- **init**.py
|
||||
- **main**.py
|
||||
- routes.py
|
||||
- templates/
|
||||
- index.html
|
||||
- static/
|
||||
- style.css
|
||||
- requirements.txt
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"label": "Python: Flask",
|
||||
"adapter": "Debugpy",
|
||||
"request": "launch",
|
||||
"module": "app",
|
||||
"cwd": "$ZED_WORKTREE_ROOT",
|
||||
"env": {
|
||||
"FLASK_APP": "app",
|
||||
"FLASK_DEBUG": "1"
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
"--reload", // Enables Flask reloader that watches for file changes
|
||||
"--debugger" // Enables Flask debugger
|
||||
],
|
||||
"autoReload": {
|
||||
"enable": true
|
||||
},
|
||||
"jinja": true,
|
||||
"justMyCode": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### Rust/C++/C
|
||||
|
||||
##### Using pre-built binary
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"label": "Debug native binary",
|
||||
"program": "$ZED_WORKTREE_ROOT/build/binary",
|
||||
"request": "launch",
|
||||
"adapter": "CodeLLDB" // GDB is available on non arm macs as well as linux
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
##### Build binary then debug
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"label": "Build & Debug native binary",
|
||||
"build": {
|
||||
"command": "cargo",
|
||||
"args": ["build"]
|
||||
},
|
||||
"program": "$ZED_WORKTREE_ROOT/target/debug/binary",
|
||||
"request": "launch",
|
||||
"adapter": "CodeLLDB" // GDB is available on non arm macs as well as linux
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Breakpoints
|
||||
|
||||
Zed currently supports these types of breakpoints
|
||||
Zed currently supports these types of breakpoints:
|
||||
|
||||
- Standard Breakpoints: Stop at the breakpoint when it's hit
|
||||
- Log Breakpoints: Output a log message instead of stopping at the breakpoint when it's hit
|
||||
- Conditional Breakpoints: Stop at the breakpoint when it's hit if the condition is met
|
||||
- Hit Breakpoints: Stop at the breakpoint when it's hit a certain number of times
|
||||
|
||||
Standard breakpoints can be toggled by left clicking on the editor gutter or using the Toggle Breakpoint action. Right clicking on a breakpoint or on a code runner symbol brings up the breakpoint context menu. This has options for toggling breakpoints and editing log breakpoints.
|
||||
Standard breakpoints can be toggled by left-clicking on the editor gutter or using the Toggle Breakpoint action. Right-clicking on a breakpoint or on a code runner symbol brings up the breakpoint context menu. This has options for toggling breakpoints and editing log breakpoints.
|
||||
|
||||
Other kinds of breakpoints can be toggled/edited by right clicking on the breakpoint icon in the gutter and selecting the desired option.
|
||||
Other kinds of breakpoints can be toggled/edited by right-clicking on the breakpoint icon in the gutter and selecting the desired option.
|
||||
|
||||
## Settings
|
||||
|
||||
|
@ -81,8 +173,8 @@ Other kinds of breakpoints can be toggled/edited by right clicking on the breakp
|
|||
- `save_breakpoints`: Whether the breakpoints should be reused across Zed sessions.
|
||||
- `button`: Whether to show the debug button in the status bar.
|
||||
- `timeout`: Time in milliseconds until timeout error when connecting to a TCP debug adapter.
|
||||
- `log_dap_communications`: Whether to log messages between active debug adapters and Zed
|
||||
- `format_dap_log_messages`: Whether to format dap messages in when adding them to debug adapter logger
|
||||
- `log_dap_communications`: Whether to log messages between active debug adapters and Zed.
|
||||
- `format_dap_log_messages`: Whether to format DAP messages when adding them to the debug adapter logger.
|
||||
|
||||
### Stepping granularity
|
||||
|
||||
|
@ -163,7 +255,7 @@ Other kinds of breakpoints can be toggled/edited by right clicking on the breakp
|
|||
### Timeout
|
||||
|
||||
- Description: Time in milliseconds until timeout error when connecting to a TCP debug adapter.
|
||||
- Default: 2000ms
|
||||
- Default: 2000
|
||||
- Setting: debugger.timeout
|
||||
|
||||
**Options**
|
||||
|
@ -198,7 +290,7 @@ Other kinds of breakpoints can be toggled/edited by right clicking on the breakp
|
|||
|
||||
### Format Dap Log Messages
|
||||
|
||||
- Description: Whether to format dap messages in when adding them to debug adapter logger. (Used for DAP development)
|
||||
- Description: Whether to format DAP messages when adding them to the debug adapter logger. (Used for DAP development)
|
||||
- Default: false
|
||||
- Setting: debugger.format_dap_log_messages
|
||||
|
||||
|
@ -218,8 +310,5 @@ Other kinds of breakpoints can be toggled/edited by right clicking on the breakp
|
|||
|
||||
The Debugger supports the following theme options:
|
||||
|
||||
/// Color used to accent some of the debugger's elements
|
||||
/// Only accents breakpoint & breakpoint related symbols right now
|
||||
|
||||
**debugger.accent**: Color used to accent breakpoint & breakpoint related symbols
|
||||
**debugger.accent**: Color used to accent breakpoint & breakpoint-related symbols
|
||||
**editor.debugger_active_line.background**: Background color of active debug line
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue