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:
Anthony Eid 2025-05-30 04:22:16 +03:00 committed by GitHub
parent a387bf5f54
commit 804de3316e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 310 additions and 22 deletions

1
Cargo.lock generated
View file

@ -15588,6 +15588,7 @@ dependencies = [
"futures 0.3.31",
"gpui",
"hex",
"log",
"parking_lot",
"pretty_assertions",
"proto",

View file

@ -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
}
}

View file

@ -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"] }

View file

@ -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"),
}
}
}

View file

@ -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