1---
2title: Debugger Extensions
3description: "Debugger Extensions for Zed extensions."
4---
5
6# Debugger Extensions
7
8[Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol) Servers can be exposed as extensions for use in the [debugger](../debugger.md).
9
10## Defining Debugger Extensions
11
12A given extension may provide one or more DAP servers.
13Each DAP server must be registered in the `extension.toml`:
14
15```toml
16[debug_adapters.my-debug-adapter]
17# Optional relative path to the JSON schema for the debug adapter configuration schema. Defaults to `debug_adapter_schemas/$DEBUG_ADAPTER_NAME_ID.json`.
18# Note that while this field is optional, a schema is mandatory.
19schema_path = "relative/path/to/schema.json"
20```
21
22Then, in the Rust code for your extension, implement the `get_dap_binary` method on your extension:
23
24```rust
25impl zed::Extension for MyExtension {
26 fn get_dap_binary(
27 &mut self,
28 adapter_name: String,
29 config: DebugTaskDefinition,
30 user_provided_debug_adapter_path: Option<String>,
31 worktree: &Worktree,
32 ) -> Result<DebugAdapterBinary, String>;
33}
34```
35
36This method should return the command to start up a debug adapter protocol server, along with any arguments or environment variables necessary for it to function.
37
38If you need to download the DAP server from an external source (GitHub Releases, npm, etc.), you can also do that in this function. Make sure to check for updates only periodically, as this function is called whenever a user spawns a new debug session with your debug adapter.
39
40You must also implement `dap_request_kind`. This function is used to determine whether a given debug scenario will _launch_ a new debuggee or _attach_ to an existing one.
41We also use it to determine that a given debug scenario requires running a _locator_.
42
43```rust
44impl zed::Extension for MyExtension {
45 fn dap_request_kind(
46 &mut self,
47 _adapter_name: String,
48 _config: Value,
49 ) -> Result<StartDebuggingRequestArgumentsRequest, String>;
50}
51```
52
53These two functions are sufficient to expose your debug adapter in `debug.json`-based user workflows, but you should strongly consider implementing `dap_config_to_scenario` as well.
54
55```rust
56impl zed::Extension for MyExtension {
57 fn dap_config_to_scenario(
58 &mut self,
59 _adapter_name: DebugConfig,
60 ) -> Result<DebugScenario, String>;
61}
62```
63
64`dap_config_to_scenario` is used when the user spawns a session via new process modal UI. At a high level, it takes a generic debug configuration (that isn't specific to any
65debug adapter) and tries to turn it into a concrete debug scenario for your adapter.
66Put another way, it is supposed to answer the question: "Given a program, a list of arguments, current working directory and environment variables, what would the configuration for spawning this debug adapter look like?".
67
68## Defining Debug Locators
69
70Zed offers an automatic way to create debug scenarios with _debug locators_.
71A locator locates the debug target and figures out how to spawn a debug session for it. Thanks to locators, we can automatically convert existing user tasks (e.g. `cargo run`) and convert them into debug scenarios (e.g. `cargo build` followed by spawning a debugger with `target/debug/my_program` as the program to debug).
72
73> Your extension can define its own debug locators even if it does not expose a debug adapter. We strongly recommend doing so when your extension already exposes language tasks, as it allows users to spawn a debug session without having to manually configure the debug adapter.
74
75Locators can (but don't have to) be agnostic to the debug adapter they are used with. They are responsible for locating the debug target and figuring out how to spawn a debug session for it. This lets extensions share locator logic across adapters.
76
77Your extension can define one or more debug locators. Each debug locator must be registered in the `extension.toml`:
78
79```toml
80[debug_locators.my-debug-locator]
81```
82
83Locators have two components.
84First, each locator is ran on each available task to figure out if any of the available locators can provide a debug scenario for a given task. This is done by calling `dap_locator_create_scenario`.
85
86```rust
87impl zed::Extension for MyExtension {
88 fn dap_locator_create_scenario(
89 &mut self,
90 _locator_name: String,
91 _build_task: TaskTemplate,
92 _resolved_label: String,
93 _debug_adapter_name: String,
94 ) -> Option<DebugScenario>;
95}
96```
97
98This function should return `Some` debug scenario when that scenario defines a debugging counterpart to a given user task.
99Note that a `DebugScenario` can include a [build task](../debugger.md#build-tasks). If there is one, we will execute `run_dap_locator` after a build task is finished successfully.
100
101```rust
102impl zed::Extension for MyExtension {
103 fn run_dap_locator(
104 &mut self,
105 _locator_name: String,
106 _build_task: TaskTemplate,
107 ) -> Result<DebugRequest, String>;
108}
109```
110
111`run_dap_locator` is useful in case you cannot determine a build target deterministically. Some build systems may produce artifacts whose names are not known up-front.
112Note however that you do _not_ need to go through a 2-phase resolution; if you can determine the full debug configuration with just `dap_locator_create_scenario`, you can omit `build` property on a returned `DebugScenario`. Please also note that your locator **will be** called with tasks it's unlikely to accept; thus you should take some effort to return `None` early before performing any expensive operations.
113
114## Available Extensions
115
116See DAP servers published as extensions [on Zed's site](https://zed.dev/extensions?filter=debug-adapters).
117
118Review their repositories to see common implementation patterns and structure.
119
120## Testing
121
122To test your new Debug Adapter Protocol server extension, you can [install it as a dev extension](./developing-extensions.md#developing-an-extension-locally).