debugger.md

  1# Debugger
  2
  3Zed uses the [Debug Adapter Protocol (DAP)](https://microsoft.github.io/debug-adapter-protocol/) to provide debugging functionality across multiple programming languages.
  4DAP is a standardized protocol that defines how debuggers, editors, and IDEs communicate with each other.
  5It allows Zed to support various debuggers without needing to implement language-specific debugging logic.
  6
  7This protocol enables features like setting breakpoints, stepping through code, inspecting variables,
  8and more, in a consistent manner across different programming languages and runtime environments.
  9
 10> We currently offer onboarding support for users. We are eager to hear from you if you encounter any issues or have suggestions for improvement for our debugging experience.
 11> You can schedule a call via [Cal.com](https://cal.com/team/zed-research/debugger)
 12
 13## Supported Debug Adapters
 14
 15Zed supports a variety of debug adapters for different programming languages out of the box:
 16
 17- JavaScript ([vscode-js-debug](https://github.com/microsoft/vscode-js-debug.git)): Enables debugging of Node.js applications, including setting breakpoints, stepping through code, and inspecting variables in JavaScript.
 18
 19- Python ([debugpy](https://github.com/microsoft/debugpy.git)): Provides debugging capabilities for Python applications, supporting features like remote debugging, multi-threaded debugging, and Django/Flask application debugging.
 20
 21- LLDB ([CodeLLDB](https://github.com/vadimcn/codelldb.git)): A powerful debugger for Rust, C, C++, and some other compiled languages, offering low-level debugging features and support for Apple platforms. (For Swift, [see below](#swift).)
 22
 23- GDB ([GDB](https://sourceware.org/gdb/)): The GNU Debugger, which supports debugging for multiple programming languages including C, C++, Go, and Rust, across various platforms.
 24
 25- Go ([Delve](https://github.com/go-delve/delve)): Delve, a debugger for the Go programming language, offering both local and remote debugging capabilities with full support for Go's runtime and standard library.
 26
 27- PHP ([Xdebug](https://xdebug.org/)): Provides debugging and profiling capabilities for PHP applications, including remote debugging and code coverage analysis.
 28
 29- Ruby ([rdbg](https://github.com/ruby/debug)): Provides debugging for Ruby.
 30
 31These adapters enable Zed to provide a consistent debugging experience across multiple languages while leveraging the specific features and capabilities of each debugger.
 32
 33> Is your desired debugger not listed? You can install a [Debug Adapter extension](https://zed.dev/extensions?filter=debug-adapters) to add support for your favorite debugger.
 34> If that's not enough, you can contribute by creating an extension yourself. Check out our [debugger extensions](extensions/debugger-extensions.md) documentation for more information.
 35
 36## Getting Started
 37
 38For 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.
 39
 40For more advanced use cases, you can create debug configurations by directly editing the `.zed/debug.json` file in your project root directory.
 41
 42You can then use the `New Session Modal` to select a configuration and start debugging.
 43
 44### Launching & Attaching
 45
 46Zed debugger offers two ways to debug your program; you can either _launch_ a new instance of your program or _attach_ to an existing process.
 47Which one you choose depends on what you are trying to achieve.
 48
 49When launching a new instance, Zed (and the underlying debug adapter) can often do a better job at picking up the debug information compared to attaching to an existing process, since it controls the lifetime of a whole program.
 50Running unit tests or a debug build of your application is a good use case for launching.
 51
 52Compared to launching, attaching to an existing process might seem inferior, but that's far from truth; there are cases where you cannot afford to restart your program, because for example, the bug is not reproducible outside of a production environment or some other circumstances.
 53
 54## Configuration
 55
 56While configuration fields are debug adapter-dependent, most adapters support the following fields:
 57
 58```json
 59[
 60  {
 61    // The label for the debug configuration and used to identify the debug session inside the debug panel & new session modal
 62    "label": "Example Start debugger config",
 63    // The debug adapter that Zed should use to debug the program
 64    "adapter": "Example adapter name",
 65    // Request:
 66    //  - launch: Zed will launch the program if specified or shows a debug terminal with the right configuration
 67    //  - attach: Zed will attach to a running program to debug it or when the process_id is not specified we will show a process picker (only supported for node currently)
 68    "request": "launch",
 69    // program: The program that you want to debug
 70    // This field supports path resolution with ~ or . symbols
 71    "program": "path_to_program",
 72    // cwd: defaults to the current working directory of your project ($ZED_WORKTREE_ROOT)
 73    "cwd": "$ZED_WORKTREE_ROOT"
 74  }
 75]
 76```
 77
 78All configuration fields support [task variables](./tasks.md#variables).
 79
 80### Build tasks
 81
 82Zed also allows embedding a Zed task in a `build` field 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.
 83
 84```json
 85[
 86  {
 87    "label": "Build Binary",
 88    "adapter": "CodeLLDB",
 89    "program": "path_to_program",
 90    "request": "launch",
 91    "build": {
 92      "command": "make",
 93      "args": ["build", "-j8"]
 94    }
 95  }
 96]
 97```
 98
 99Build tasks can also refer to the existing tasks by unsubstituted label:
100
101```json
102[
103  {
104    "label": "Build Binary",
105    "adapter": "CodeLLDB",
106    "program": "path_to_program",
107    "request": "launch",
108    "build": "my build task" // Or "my build task for $ZED_FILE"
109  }
110]
111```
112
113### Automatic scenario creation
114
115Given a Zed task, Zed can automatically create a scenario for you. Automatic scenario creation also powers our scenario creation from gutter.
116Automatic scenario creation is currently supported for Rust, Go, and Python. JavaScript/TypeScript support is being worked on.
117
118### Example Configurations
119
120#### JavaScript
121
122##### Debug Active File
123
124```json
125[
126  {
127    "label": "Debug with node",
128    "adapter": "JavaScript",
129    "program": "$ZED_FILE",
130    "request": "launch",
131    "console": "integratedTerminal",
132    "type": "pwa-node"
133  }
134]
135```
136
137##### Attach debugger to a server running in web browser (`npx serve`)
138
139Given an externally-ran web server (e.g., with `npx serve` or `npx live-server`) one can attach to it and open it with a browser.
140
141```json
142[
143  {
144    "label": "Inspect ",
145    "adapter": "JavaScript",
146    "type": "pwa-chrome",
147    "request": "launch",
148    "url": "http://localhost:5500", // Fill your URL here.
149    "program": "$ZED_FILE",
150    "webRoot": "${ZED_WORKTREE_ROOT}"
151  }
152]
153```
154
155#### Python
156
157##### Debug Active File
158
159```json
160[
161  {
162    "label": "Python Active File",
163    "adapter": "Debugpy",
164    "program": "$ZED_FILE",
165    "request": "launch"
166  }
167]
168```
169
170##### Flask App
171
172For a common Flask Application with a file structure similar to the following:
173
174```
175.venv/
176app/
177  init.py
178  main.py
179  routes.py
180templates/
181  index.html
182static/
183  style.css
184requirements.txt
185```
186
187…the following configuration can be used:
188
189```json
190[
191  {
192    "label": "Python: Flask",
193    "adapter": "Debugpy",
194    "request": "launch",
195    "module": "app",
196    "cwd": "$ZED_WORKTREE_ROOT",
197    "env": {
198      "FLASK_APP": "app",
199      "FLASK_DEBUG": "1"
200    },
201    "args": [
202      "run",
203      "--reload", // Enables Flask reloader that watches for file changes
204      "--debugger" // Enables Flask debugger
205    ],
206    "autoReload": {
207      "enable": true
208    },
209    "jinja": true,
210    "justMyCode": true
211  }
212]
213```
214
215#### Rust/C++/C
216
217##### Using pre-built binary
218
219```json
220[
221  {
222    "label": "Debug native binary",
223    "program": "$ZED_WORKTREE_ROOT/build/binary",
224    "request": "launch",
225    "adapter": "CodeLLDB" // GDB is available on non arm macs as well as linux
226  }
227]
228```
229
230##### Build binary then debug
231
232```json
233[
234  {
235    "label": "Build & Debug native binary",
236    "build": {
237      "command": "cargo",
238      "args": ["build"]
239    },
240    "program": "$ZED_WORKTREE_ROOT/target/debug/binary",
241    "request": "launch",
242    "adapter": "CodeLLDB" // GDB is available on non arm macs as well as linux
243  }
244]
245```
246
247#### TypeScript
248
249##### Attach debugger to a server running in web browser (`npx serve`)
250
251Given an externally-ran web server (e.g., with `npx serve` or `npx live-server`) one can attach to it and open it with a browser.
252
253```json
254[
255  {
256    "label": "Launch Chrome (TypeScript)",
257    "adapter": "JavaScript",
258    "type": "pwa-chrome",
259    "request": "launch",
260    "url": "http://localhost:5500",
261    "program": "$ZED_FILE",
262    "webRoot": "${ZED_WORKTREE_ROOT}",
263    "sourceMaps": true,
264    "build": {
265      "command": "npx",
266      "args": ["tsc"]
267    }
268  }
269]
270```
271
272#### Go
273
274Zed uses [delve](https://github.com/go-delve/delve?tab=readme-ov-file) to debug Go applications.
275Zed will automatically create debug scenarios for `func main` in your main packages, and also
276for any tests, so you can use the Play button in the gutter to debug these without configuration.
277
278##### Debug Go Packages
279
280To debug a specific package, you can do so by setting the Delve mode to "debug". In this case "program" should be set to the package name.
281
282```json
283[
284  {
285    "label": "Go (Delve)",
286    "adapter": "Delve",
287    "program": "$ZED_FILE",
288    "request": "launch",
289    "mode": "debug"
290  }
291]
292```
293
294```json
295[
296  {
297    "label": "Run server",
298    "adapter": "Delve",
299    "request": "launch",
300    "mode": "debug",
301    // For Delve, the program can be a package name
302    "program": "./cmd/server"
303    // "args": [],
304    // "buildFlags": [],
305  }
306]
307```
308
309##### Debug Go Tests
310
311To debug the tests for a package, set the Delve mode to "test".
312The "program" is still the package name, and you can use the "buildFlags" to do things like set tags, and the "args" to set args on the test binary. (See `go help testflags` for more information on doing that).
313
314```json
315[
316  {
317    "label": "Run integration tests",
318    "adapter": "Delve",
319    "request": "launch",
320    "mode": "test",
321    "program": ".",
322    "buildFlags": ["-tags", "integration"]
323    // To filter down to just the test your cursor is in:
324    // "args": ["-test.run", "$ZED_SYMBOL"]
325  }
326]
327```
328
329##### Build and debug separately
330
331If you need to build your application with a specific command, you can use the "exec" mode of Delve. In this case "program" should point to an executable,
332and the "build" command should build that.
333
334```json
335{
336  "label": "Debug Prebuilt Unit Tests",
337  "adapter": "Delve",
338  "request": "launch",
339  "mode": "exec",
340  "program": "${ZED_WORKTREE_ROOT}/__debug_unit",
341  "args": ["-test.v", "-test.run=${ZED_SYMBOL}"],
342  "build": {
343    "command": "go",
344    "args": [
345      "test",
346      "-c",
347      "-tags",
348      "unit",
349      "-gcflags\"all=-N -l\"",
350      "-o",
351      "__debug_unit",
352      "./pkg/..."
353    ]
354  }
355}
356```
357
358##### Attaching to an existing instance of Delve
359
360You might find yourself needing to connect to an existing instance of Delve that's not necessarily running on your machine; in such case, you can use `tcp_arguments` to instrument Zed's connection to Delve.
361
362```
363{
364  "adapter": "Delve",
365  "label": "Connect to a running Delve instance",
366  "program": "/Users/zed/Projects/language_repositories/golang/hello/hello",
367  "cwd": "/Users/zed/Projects/language_repositories/golang/hello",
368  "args": [],
369  "env": {},
370  "request": "launch",
371  "mode": "exec",
372  "stopOnEntry": false,
373  "tcp_connection": { "host": "123.456.789.012", "port": 53412 }
374}
375```
376
377In such case Zed won't spawn a new instance of Delve, as it opts to use an existing one. The consequence of this is that _there will be no terminal_ in Zed; you have to interact with the Delve instance directly, as it handles stdin/stdout of the debuggee.
378
379#### Swift
380
381Out-of-the-box support for debugging Swift programs will be provided by the Swift extension for Zed in the near future. In the meantime, the builtin CodeLLDB adapter can be used with some customization. On macOS, you'll need to locate the `lldb-dap` binary that's part of Apple's LLVM toolchain by running `which lldb-dap`, then point Zed to it in your project's `.zed/settings.json`:
382
383```json
384{
385  "dap": {
386    "CodeLLDB": {
387      "binary": "/Applications/Xcode.app/Contents/Developer/usr/bin/lldb-dap", // example value, may vary between systems
388      "args": []
389    }
390  }
391}
392```
393
394#### Ruby
395
396To run a ruby task in the debugger, you will need to configure it in the `.zed/debug.json` file in your project. We don't yet have automatic detection of ruby tasks, nor do we support connecting to an existing process.
397
398The configuration should look like this:
399
400```json
401[
402  {
403    "adapter": "Ruby",
404    "label": "Run CLI",
405    "script": "cli.rb"
406    // If you want to customize how the script is run (for example using bundle exec)
407    // use "command" instead.
408    // "command": "bundle exec cli.rb"
409    //
410    // "args": []
411    // "env": {}
412    // "cwd": ""
413  }
414]
415```
416
417## Breakpoints
418
419To set a breakpoint, simply click next to the line number in the editor gutter.
420Breakpoints can be tweaked depending on your needs; to access additional options of a given breakpoint, right-click on the breakpoint icon in the gutter and select the desired option.
421At present, you can:
422
423- Add a log to a breakpoint, which will output a log message whenever that breakpoint is hit.
424- Make the breakpoint conditional, which will only stop at the breakpoint when the condition is met. The syntax for conditions is adapter-specific.
425- Add a hit count to a breakpoint, which will only stop at the breakpoint after it's hit a certain number of times.
426- Disable a breakpoint, which will prevent it from being hit while leaving it visible in the gutter.
427
428Some debug adapters (e.g. CodeLLDB and JavaScript) will also _verify_ whether your breakpoints can be hit; breakpoints that cannot be hit are surfaced more prominently in the UI.
429
430All breakpoints enabled for a given project are also listed in "Breakpoints" item in your debugging session UI. From "Breakpoints" item in your UI you can also manage exception breakpoints.
431The debug adapter will then stop whenever an exception of a given kind occurs. Which exception types are supported depends on the debug adapter.
432
433## Settings
434
435- `dock`: Determines the position of the debug panel in the UI.
436- `stepping_granularity`: Determines the stepping granularity.
437- `save_breakpoints`: Whether the breakpoints should be reused across Zed sessions.
438- `button`: Whether to show the debug button in the status bar.
439- `timeout`: Time in milliseconds until timeout error when connecting to a TCP debug adapter.
440- `log_dap_communications`: Whether to log messages between active debug adapters and Zed.
441- `format_dap_log_messages`: Whether to format DAP messages when adding them to the debug adapter logger.
442
443### Dock
444
445- Description: The position of the debug panel in the UI.
446- Default: `bottom`
447- Setting: debugger.dock
448
449**Options**
450
4511. `left` - The debug panel will be docked to the left side of the UI.
4522. `right` - The debug panel will be docked to the right side of the UI.
4533. `bottom` - The debug panel will be docked to the bottom of the UI.
454
455```json
456"debugger": {
457  "dock": "bottom"
458},
459```
460
461### Stepping granularity
462
463- Description: The Step granularity that the debugger will use
464- Default: line
465- Setting: debugger.stepping_granularity
466
467**Options**
468
4691. Statement - The step should allow the program to run until the current statement has finished executing.
470   The meaning of a statement is determined by the adapter and it may be considered equivalent to a line.
471   For example 'for(int i = 0; i < 10; i++)' could be considered to have 3 statements 'int i = 0', 'i < 10', and 'i++'.
472
473```json
474{
475  "debugger": {
476    "stepping_granularity": "statement"
477  }
478}
479```
480
4812. Line - The step should allow the program to run until the current source line has executed.
482
483```json
484{
485  "debugger": {
486    "stepping_granularity": "line"
487  }
488}
489```
490
4913. Instruction - The step should allow one instruction to execute (e.g. one x86 instruction).
492
493```json
494{
495  "debugger": {
496    "stepping_granularity": "instruction"
497  }
498}
499```
500
501### Save Breakpoints
502
503- Description: Whether the breakpoints should be saved across Zed sessions.
504- Default: true
505- Setting: debugger.save_breakpoints
506
507**Options**
508
509`boolean` values
510
511```json
512{
513  "debugger": {
514    "save_breakpoints": true
515  }
516}
517```
518
519### Button
520
521- Description: Whether the button should be displayed in the debugger toolbar.
522- Default: true
523- Setting: debugger.show_button
524
525**Options**
526
527`boolean` values
528
529```json
530{
531  "debugger": {
532    "show_button": true
533  }
534}
535```
536
537### Timeout
538
539- Description: Time in milliseconds until timeout error when connecting to a TCP debug adapter.
540- Default: 2000
541- Setting: debugger.timeout
542
543**Options**
544
545`integer` values
546
547```json
548{
549  "debugger": {
550    "timeout": 3000
551  }
552}
553```
554
555### Log Dap Communications
556
557- Description: Whether to log messages between active debug adapters and Zed. (Used for DAP development)
558- Default: false
559- Setting: debugger.log_dap_communications
560
561**Options**
562
563`boolean` values
564
565```json
566{
567  "debugger": {
568    "log_dap_communications": true
569  }
570}
571```
572
573### Format Dap Log Messages
574
575- Description: Whether to format DAP messages when adding them to the debug adapter logger. (Used for DAP development)
576- Default: false
577- Setting: debugger.format_dap_log_messages
578
579**Options**
580
581`boolean` values
582
583```json
584{
585  "debugger": {
586    "format_dap_log_messages": true
587  }
588}
589```
590
591### Customizing Debug Adapters
592
593- Description: Custom program path and arguments to override how Zed launches a specific debug adapter.
594- Default: Adapter-specific
595- Setting: `dap.$ADAPTER.binary` and `dap.$ADAPTER.args`
596
597You can pass `binary`, `args`, or both. `binary` should be a path to a _debug adapter_ (like `lldb-dap`) not a _debugger_ (like `lldb` itself). The `args` setting overrides any arguments that Zed would otherwise pass to the adapter.
598
599```json
600{
601  "dap": {
602    "CodeLLDB": {
603      "binary": "/Users/name/bin/lldb-dap",
604      "args": ["--wait-for-debugger"]
605    }
606  }
607}
608```
609
610## Theme
611
612The Debugger supports the following theme options:
613
614- `debugger.accent`: Color used to accent breakpoint & breakpoint-related symbols
615- `editor.debugger_active_line.background`: Background color of active debug line
616
617## Troubleshooting
618
619If you're running into problems with the debugger, please [open a GitHub issue](https://github.com/zed-industries/zed/issues/new?template=04_bug_debugger.yml) or [schedule an onboarding call](https://cal.com/team/zed-research/debugger) with us so we can help understand and fix your issue.
620
621There are also some features you can use to gather more information about the problem:
622
623- When you have a session running in the debug panel, you can run the `dev: copy debug adapter arguments` action to copy a JSON blob to the clipboard that describes how Zed initialized the session. This is especially useful when the session failed to start, and is great context to add if you open a GitHub issue.
624- You can also use the `dev: open debug adapter logs` action to see a trace of all of Zed's communications with debug adapters during the most recent debug sessions.