Skip to content
| Marketplace
Sign in
Visual Studio Code>Debuggers>dblNew to Visual Studio Code? Get it now.
dbl

dbl

David Wright

| (0) | Free
Launch debug sessions from the terminal via the dbl CLI
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

dbl

Debug launcher. Pronounced "tubel"

Type dbl <command> in your editor's terminal and it launches that command in a debug session. Works with Neovim and VSCode.

dbl ./build/app --flag value
dbl bazel run --config=dbg //pkg:target -- --arg
dbl bazel test --config=dbg //pkg:test -- --arg
dbl cargo run -- --arg
dbl cargo test --test my_test -- --arg
dbl cmake run -B build -DCMAKE_BUILD_TYPE=Debug --target myapp -- --arg
dbl cmake test -B build -DCMAKE_BUILD_TYPE=Debug --target mytest -- --arg
dbl ctest --test-dir build -R mytest -- --arg
dbl python script.py arg
dbl --debugger=codelldb ./app    # override adapter detection

Prerequisites

  • Bazel (for building dbl from source)
  • One of:
    • Neovim 0.10+ with nvim-dap
    • VSCode with the dbl extension

Install

CLI

Homebrew (macOS / Linux)

brew install dav1d-wright/dbl/dbl

From source (Cargo)

cargo install --path cli

From source (Bazel)

bazel run //cli:install

This builds the CLI binary and copies it to ~/.local/bin/dbl. Ensure ~/.local/bin is on your PATH.

Neovim plugin

Install this repo as a Neovim plugin. The lua/ and plugin/ directories are at the repo root, so any plugin manager works directly.

With lazy.nvim (GitLab):

{ url = "https://gitlab.com/david_wright/dbl.git", config = function() require("dbl").setup({}) end }

GitHub mirror:

{ "dav1d-wright/dbl", config = function() require("dbl").setup({}) end }

VSCode extension

Build and install the extension from the vscode/ directory:

cd vscode
npm ci && npm run build
npx vsce package --no-dependencies
code --install-extension dbl-0.1.0.vsix

The extension automatically sets $DBL in all integrated terminals. No additional configuration is needed for the default adapter mappings.

Override adapters or enable stop-on-entry in VSCode settings:

{
  "dbl.adapters": { "c": "cppdbg" },
  "dbl.stopOnEntry": false
}

Adapter configuration

dbl detects the language of your program and maps it to a DAP adapter. The defaults cover common setups:

Language Adapter
C, C++, Rust, Zig, Objective-C, native binaries codelldb
Python debugpy
Go delve

Override or extend mappings in setup():

require("dbl").setup({
  adapters = {
    c = "cppdbg",       -- use cppdbg instead of codelldb for C
    java = "java-dbg",  -- add a new language
  },
})

The --debugger flag bypasses detection entirely:

dbl --debugger=lldb-dap ./myapp

Usage

Run dbl from your editor's integrated terminal. In Neovim, you can also use the :Dbl command:

:Dbl bazel run --config=dbg //pkg:target

:Dbl runs dbl in the background and reports errors via vim.notify. It accepts the same arguments as the CLI.

Plain binaries

dbl ./build/myapp --flag value

Resolves the binary to an absolute path and passes remaining arguments through.

Bazel targets

dbl bazel run --config=dbg //pkg:target -- --user-arg
dbl bazel test --config=dbg //pkg:test -- --user-arg

Replaces run/test with build, forwards your flags to bazel cquery and bazel build, and resolves the binary. Arguments after -- are passed to the debugged program, not to bazel. Pass --config=dbg or --compilation_mode=dbg to build with debug symbols.

bazel test targets get the test environment variables that bazel's test runner normally sets: TEST_TMPDIR, TEST_SRCDIR, BAZEL_TEST, TEST_TARGET, and HOME. This allows test binaries that depend on runfiles or temp directories to work correctly under the debugger.

Cargo targets

dbl cargo run -- --user-arg
dbl cargo test --test my_test -- --user-arg

Replaces run/test with build, forwards your flags to cargo build, and resolves the binary using --message-format=json. Arguments after -- are passed to the debugged program, not to cargo.

CMake targets

dbl cmake run -B build -DCMAKE_BUILD_TYPE=Debug --target myapp -- --user-arg
dbl cmake test -B build -DCMAKE_BUILD_TYPE=Debug --target mytest -- --user-arg

cmake run and cmake test are dbl subcommands (cmake has no native run/test for individual targets). Uses cmake's own flags: -B sets the build directory (defaults to cwd), --target/-t selects the target. -D flags are forwarded to cmake configure; all other flags are forwarded to cmake --build. Arguments after -- are passed to the debugged program. Uses the CMake File API to discover the artifact path. Auto-configures if the build directory is not set up.

CTest

dbl ctest --test-dir build -R mytest -- --user-arg

All standard ctest filtering flags work: -R (regex match), -E (regex exclude), -L/-LE (label match/exclude), -C (configuration), -I (range). Requires exactly one test match. Arguments after -- are appended to the test command.

Python

dbl python3 script.py --arg

Resolves the interpreter path and keeps the script and args separate. debugpy receives the correct interpreter path.

Options

Flag Description
--debugger=<name> Override adapter detection. Uses the given adapter name directly.

Examples

The tests/projects/ directory contains small programs you can debug with dbl. Open nvim, set breakpoints in the test projects, then run from :terminal or via :Dbl:

# C (Bazel)
dbl bazel run --config=dbg //tests/projects/bazel_app:app -- arg1
dbl bazel test --config=dbg //tests/projects/bazel_app:app_test

# Rust (Bazel)
dbl bazel run --config=dbg //tests/projects/bazel_rs_app:app
dbl bazel test --config=dbg //tests/projects/bazel_rs_app:app_test

# Python (Bazel)
dbl bazel run //tests/projects/bazel_py_app:app
dbl bazel test //tests/projects/bazel_py_app:app_test

# Rust (Cargo)
cd tests/projects/cargo_app
dbl cargo run
dbl cargo test --test cargo_app_test

# Python (direct)
dbl python3 tests/projects/python_app/app.py

# C (CMake)
dbl cmake run -B tests/projects/cmake_app/build \
    -S tests/projects/cmake_app -DCMAKE_BUILD_TYPE=Debug --target cmake_app
dbl cmake test -B tests/projects/cmake_app/build \
    -S tests/projects/cmake_app -DCMAKE_BUILD_TYPE=Debug --target cmake_app_test

Or equivalently from nvim's command line:

:Dbl bazel run --config=dbg //tests/projects/bazel_app:app -- arg1
:Dbl python3 tests/projects/python_app/app.py

Dogfooding

Debug dbl with dbl. From nvim's :terminal:

dbl bazel run --config=dbg //cli:dbl -- --help

This builds the CLI with debug symbols and launches a codelldb debug session. Set breakpoints in the Rust source before running.

Roadmap

  • [ ] Environment variable forwarding. FOO=bar dbl ./app currently assigns FOO=bar to the dbl process, not the debugged program. A --env flag or -- separator for env vars would fix this.
  • [ ] Custom tool paths. dbl finds cmake, bazel, python/python3 via $PATH. A --cmake= / --bazel= flag would allow overriding.
  • [ ] Execution-phase flag passthrough. dbl replaces run/test with build, so flags that affect execution (e.g. bazel's --run_under) are silently ignored.
  • [ ] Multi-target debugging. Each invocation debugs one program. Wildcard patterns like //pkg/... or //pkg:all are rejected.

Build and test

bazel build //cli:dbl          # build the CLI binary
bazel test //...               # run all tests (CLI, nvim plugin, integration)
cd vscode && npm test          # run VSCode extension tests

Design

terminal                          Editor
┌──────────┐  dbl/launch         ┌────────────┐
│ dbl CLI  │ ──────────────────► │ dbl plugin │ ──► debug session
│ (Rust)   │  via $DBL socket    │            │
└──────────┘                     └────────────┘

The CLI sends a JSON launch request to the editor plugin over a Unix socket ($DBL) using msgpack-rpc with method dbl/launch. The plugin handles adapter selection, validation, and launching. The protocol is editor-agnostic; each editor plugin runs its own socket server.

The CLI resolves a freeform shell command into a structured launch request in three stages:

  1. Launch resolution. Determines how to obtain the program binary. Dispatches by command shape: bazel targets are built via cquery + build, cmake targets use the CMake File API, ctest uses --show-only=json-v1, python commands resolve the interpreter path, and plain commands resolve via canonicalize.

  2. Kind detection. Analyzes the resolved file to determine its language using content analysis (hyperpolyglot, a Rust port of GitHub Linguist) and binary section scanning (goblin) for compiled languages like Go.

  3. Request assembly. Combines the resolved program, detected kind, and optional --debugger override into a launch request sent to the plugin.

Repo layout

MODULE.bazel        Bazel module definition
cli/                Rust CLI binary
  src/
    main.rs         entry point, arg parsing
    resolve.rs      command resolution, kind detection
    rpc.rs          editor RPC client (msgpack)
lua/dbl/            Neovim plugin (at repo root for plugin managers)
  init.lua          setup(), socket server, launch(), adapter mapping
  config.lua        defaults and user config
plugin/dbl.lua      :Dbl command registration
vscode/             VSCode extension
  src/
    extension.ts    activate/deactivate, $DBL injection
    server.ts       Unix socket server, msgpack-rpc handling
    launch.ts       LaunchRequest to DebugConfiguration mapping
tests/              unit, plugin, and integration tests

License

MIT. See LICENSE.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft