helix-editor/helix
Debugger
Helix integrates with any DAP-compliant debug adapter (lldb-vscode/codelldb, debugpy, delve, etc.). The protocol layer is helix-dap; the user-facing commands live in helix-term/src/commands/dap.rs.
Configuration
A debug adapter is declared per-language in languages.toml:
[language.debugger]
name = "lldb-vscode"
transport = "stdio"
command = "lldb-vscode"
quirks = { absolute_paths = true }
[[language.debugger.templates]]
name = "binary"
request = "launch"
completion = [ { name = "binary", completion = "filename" } ]
args = { program = "{0}" }transport:stdioortcp.templates: argument prompts surfaced in the:debug-startUI. Each completion entry maps to a positional argument with an editor-side completer (filename, directory, etc.).quirks: per-adapter behaviour flags. Defined onDebuggerQuirksinhelix-core/src/syntax/config.rs.
Commands and bindings
User commands sit under the space g (debug) prefix or are typable:
| Command | Purpose |
|---|---|
:debug-start [template] |
Spawn the configured adapter and launch a session. |
:debug-remote |
Attach to an already-running adapter on TCP. |
dap_toggle_breakpoint (space g b) |
Toggle a breakpoint at the cursor. |
dap_edit_condition / dap_edit_log |
Edit conditional/log breakpoint properties. |
dap_continue (space g c) |
Continue execution. |
dap_step_in / dap_step_out / dap_next |
Step controls. |
dap_pause |
Pause the running thread. |
dap_terminate |
Disconnect with terminate request. |
dap_variables |
Open variable picker for the current frame. |
dap_switch_thread / dap_switch_stack_frame |
Pickers for threads and stack frames. |
The full list lives in commands/dap.rs and the static_commands! invocation in commands.rs.
State on Editor
Editor {
debug_adapters: helix_dap::registry::Registry,
breakpoints: HashMap<PathBuf, Vec<Breakpoint>>,
// …
}Breakpoints are kept on the Editor (not on the Document) because they survive document closes and reopens. They are persisted across DAP sessions. The Breakpoint struct (helix-view/src/editor.rs) holds the line, optional column, condition, hit-condition, log-message, and verification state.
Lifecycle
sequenceDiagram
participant User
participant Cmd as commands::dap
participant Reg as Registry
participant Cli as Client
participant Adp as Debug Adapter
User->>Cmd: :debug-start
Cmd->>Reg: start adapter
Reg->>Cli: spawn (stdio/tcp)
Cli->>Adp: initialize
Adp-->>Cli: capabilities
Cmd->>Cli: launch (with template args)
Adp-->>Cli: initialized event
Cli->>Adp: setBreakpoints (from Editor::breakpoints)
Cli->>Adp: configurationDone
Adp-->>Cli: stopped (entry, breakpoint, exception, …)
Cli-->>App: event → handle_debugger_message
App->>UI: open stack frame, fetch scopes
User->>Cmd: dap_continue / dap_step_*Each stopped event triggers a fetch of the stack trace, scopes, and variables for the current frame. The active frame is rendered with a special gutter sign; the breakpoint gutter is drawn from Editor::breakpoints.
startDebugging reverse request
Some adapters (Node.js, .NET) emit a startDebugging reverse request asking the editor to spawn a child session. Helix added support for this in 25.07 (#13403) — see helix-dap/src/client.rs.
REPL (:debug-eval)
:debug-eval <expr> sends an evaluate request to the active frame and shows the result in the statusline. This is the lowest-friction way to inspect state without opening the variable picker.
Limitations
- The adapter must speak DAP over stdio or TCP. Adapters that require an in-IDE WebSocket bridge (e.g. browser debuggers via Chrome DevTools Protocol) need a wrapper.
- Helix has no inline-value rendering today (variables shown beside the line) — values live in the
dap_variablespicker instead. - Conditional breakpoints rely on the adapter's expression evaluation; debug adapters vary in support.
See also
- packages/helix-dap — protocol-level details.
- packages/helix-view —
Editor::breakpointsand the breakpoint gutter.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.