*turbo-debug.txt* A zero-config debugging experience for Neovim 0.12+ ============================================================================== CONTENTS *turbo-debug-contents* 1. Introduction .......................... |turbo-debug-introduction| 2. Installation .......................... |turbo-debug-installation| 3. Setup ................................. |turbo-debug.setup| 4. Debug Mode ............................ |turbo-debug-debug-mode| 5. Keybindings ........................... |turbo-debug.keys| 6. Breakpoints ........................... |turbo-debug-breakpoints| 7. Chrome Bars ........................... |turbo-debug-chrome| 8. UI Layout ............................. |turbo-debug-layout| 9. Adapters .............................. |turbo-debug.adapters| 10. API ................................... |turbo-debug-api| 11. Troubleshooting ....................... |turbo-debug-troubleshooting| ============================================================================== 1. Introduction *turbo-debug-introduction* turbo-debug.nvim gives you a fully-featured debugging experience out of one line of config. Under the hood it wires together nvim-dap, nvim-dap-ui, nvim-dap-virtual-text, and persistent-breakpoints into a single cohesive modal experience. Features: - Modal keybindings active only during debug sessions — single-key controls that shadow editing keys, cleanly restored on exit - Inline virtual text showing variable values in source code - Persistent breakpoints that survive Neovim restarts - Hover inspection (|K|) and watch expressions (|W|) from the code window - Floating REPL eval (|E|) - Floating status bar + control bar chrome (independent of any statusline plugin) - Zero-config adapters for 22 languages - Theme-agnostic colors (every highlight links to a standard group) ============================================================================== 2. Installation *turbo-debug-installation* Add one line to your init.lua: >lua vim.pack.add("swaits/turbo-debug") < That's it. All dependencies are managed automatically. Requires Neovim >= 0.12. ============================================================================== 3. Setup *turbo-debug.setup* Setup is optional. The plugin works with no configuration. To customize: >lua require("turbo-debug").setup({ help_on_enter = false, builtin_adapters = true, stop_on_entry_when_no_breakpoints = true, max_value_width = 2000, console_refresh_ms = 50, collapsed_scopes = { "Registers" }, clear_console_on_start = true, sidebar = "left", colorscheme = nil, active_window_highlight = true, keys = { ... }, global_keys = { ... }, adapters = { ... }, dapui = { ... }, virtual_text = { ... }, }) < *turbo-debug.setup.help_on_enter* help_on_enter ~ Type: boolean, Default: `false` Show the help popup automatically when entering debug mode. The control bar always shows `(?) help`, so most users don't need the splash. *turbo-debug.setup.builtin_adapters* builtin_adapters ~ Type: boolean, Default: `true` Register the built-in language adapters. Set to `false` to opt out of all built-in adapter registration and manage adapters yourself. *turbo-debug.setup.stop_on_entry_when_no_breakpoints* stop_on_entry_when_no_breakpoints ~ Type: boolean, Default: `true` When `c` is pressed with no breakpoints set, launch the first adapter configuration for the filetype with `stopOnEntry = true` so the debugger pauses at the program's entry point. Matches the Turbo Pascal "press key to start debugging" model. Set `false` to always run until a breakpoint. *turbo-debug.setup.max_value_width* max_value_width ~ Type: integer, Default: `2000` Per-line character cap for variable values rendered in Scopes/Watches. Values exceeding this are truncated with `…`. Default 2000 only catches pathological multi-KB dumps; normal values pass through. Set to `0` to disable truncation entirely. *turbo-debug.setup.console_refresh_ms* console_refresh_ms ~ Type: integer, Default: `50` Trailing-edge throttle (ms) for Console pane repaints when the debugged program outputs. Max `1000/console_refresh_ms` redraws per second. Prevents editor lag under high-throughput output. *turbo-debug.setup.collapsed_scopes* collapsed_scopes ~ Type: string[], Default: `{ "Registers" }` Scope names (as reported by the DAP adapter) to default-collapse. Some adapters (codelldb for Rust/C++, for example) don't mark Registers as "expensive" even though it's a huge dump. Any scope name in this list is treated as expensive — dapui auto-collapses expensive scopes. *turbo-debug.setup.clear_console_on_start* clear_console_on_start ~ Type: boolean, Default: `true` Clear the Console pane on session start/restart. The terminal channel is preserved — only the displayed scrollback is wiped. *turbo-debug.setup.sidebar* sidebar ~ Type: string, Default: `"left"` Sidebar position: `"left"` or `"right"`. Controls which side of the editor the Stacks/Scopes/Watches/Breakpoints column appears on. *turbo-debug.setup.colorscheme* colorscheme ~ Type: string|nil, Default: `nil` Optional colorscheme to switch to while debug mode is active. `nil` keeps the user's current colorscheme. Any other string value is passed to `:colorscheme`. The previous colorscheme is restored on exit. *turbo-debug.setup.active_window_highlight* active_window_highlight ~ Type: boolean, Default: `true` Dim inactive dapui panes' borders so the focused pane is visually obvious. *turbo-debug.setup.keys* keys ~ Type: table, Default: see |turbo-debug.keys| Override modal keybindings (active only during debug mode). Set any entry to `false` to disable that action entirely. *turbo-debug.setup.global_keys* global_keys ~ Type: table, Default: see |turbo-debug.keys| Override always-available keybindings. Set any entry to `false` to disable. *turbo-debug.setup.adapters* adapters ~ Type: table, Default: `{}` Override or add language adapters. Keyed by adapter name; each value is a table with `adapter` (passed to |dap.adapters|) and/or `configurations` (passed to |dap.configurations|) fields. User overrides are applied after the built-ins, so existing adapter entries are replaced. *turbo-debug.setup.dapui* dapui ~ Type: table Pass-through configuration for nvim-dap-ui's |dapui.setup()|. Override icons, controls, floating window style, render options, etc. *turbo-debug.setup.virtual_text* virtual_text ~ Type: table Pass-through configuration for nvim-dap-virtual-text. Set `virtual_text = { enabled = false }` to disable inline variable values entirely. ============================================================================== 4. Debug Mode *turbo-debug-debug-mode* Press `dd` to toggle debug mode. Entering debug mode: 1. Switches colorscheme (if |turbo-debug.setup.colorscheme| is set) 2. Applies turbo-debug highlight groups 3. Opens nvim-dap-ui (sidebar + Console pane) 4. Creates the floating status bar (top) and control bar (bottom) 5. Installs modal keybindings on every buffer 6. Enables nvim-dap-virtual-text 7. Optionally shows the help popup (|turbo-debug.setup.help_on_enter|) Exiting debug mode (any of): - `dd` again (manual toggle) - `q` when no DAP session is running - Context-aware `q`: if a session IS running, `q` terminates the session but leaves debug mode active so you can inspect the Console / watch post-mortem state. Press `q` again to exit debug mode. On exit, everything is restored: - Modal keymaps removed, any prior user mappings re-installed - Source window's original `winbar` restored - `WinSeparator` highlight restored byte-for-byte - Original colorscheme restored (if one was swapped in) - dapui panes closed, control bars removed - Virtual text disabled ============================================================================== 5. Keybindings *turbo-debug.keys* Modal keybindings are active only during debug mode. They shadow editing keys you don't need while debugging, but preserve all navigation keys. Default keymap: Key Action Mnemonic ~ `c` Continue / start Universal across debuggers `s` Step over Step `d` Step into Descend into the function `r` Step out Return from the function `C` Run to cursor Continue to cursor `x` Toggle breakpoint X marks the spot `X` Conditional breakpoint Shift variant of x `D` Clear all breakpoints Delete all `W` Watch expr under cursor Watch `K` Hover / inspect Matches LSP hover convention `E` Eval in REPL Evaluate (floating REPL) `q` Smart quit Context-aware terminate / exit `R` Restart session Rerun `?` Help popup Show keybindings Always available (under `d` prefix, with which-key support): `dd` Toggle debug mode `dx` Toggle breakpoint X marks the spot `dX` Conditional breakpoint Shift variant `dD` Clear all breakpoints Delete all `W` and `K` also work in visual mode — they operate on the visual selection. Override any key: >lua require("turbo-debug").setup({ keys = { continue = "g", -- remap a modal key step_over = false, -- disable a modal key }, global_keys = { toggle = "DD", breakpoint = "db", }, }) < Inside dapui panes (Watches / Scopes / Stacks / Breakpoints / REPL), the native dapui mappings `` / `e` / `o` / `d` / `r` / `t` still work — our modal `d` (step-into) and `r` (step-out) yield inside those buffers. Preserved keys (never shadowed in source buffers): - Navigation: `h j k l w b e f F t T / n N 0 ^ $ G g { } % [ ]` - Insert: `i a o O` - Visual/yank/edit: `v V y p u` - All Ctrl/Alt/leader combos ============================================================================== 6. Breakpoints *turbo-debug-breakpoints* Breakpoints are managed by persistent-breakpoints.nvim. They persist across Neovim restarts and are visible in the sign column at all times. Global shortcuts (always available): `dx` Toggle breakpoint `dX` Conditional breakpoint (prompts for condition) `dD` Clear all breakpoints Modal shortcuts (debug mode only): `x` `X` `D` do the same. Gutter signs (colorful emoji in modern terminals): 🔴 breakpoint 🟡 conditional breakpoint ⭕ rejected breakpoint (DAP server couldn't set it) 👉 current execution line (paired with `👈 REASON` virtual text) 📝 logpoint ============================================================================== 7. Chrome Bars *turbo-debug-chrome* Debug mode opens two floating bars, independent of any statusline plugin: Status bar (top, 2 rows) shows: - `turbo-debug` brand - `dap.status()` progress text (right of brand) - State chip: ` DEBUG · READY ` / ` · RUNNING ` / ` · PAUSED ` Control bar (bottom, 2 rows, above your statusline) shows: - Clickable buttons for `(c)ontinue`, `(s)tep` over, `(d)escend` into, `(r)eturn` out, `(R)estart` (during session), `(q)uit` - Italic qualifiers (`over`, `into`, `out`) shown inline when width allows - `(?) help` anchored on the right - Click any button to fire its action Both bars update live on DAP state transitions (|User DapProgressUpdate|) and on editor resize. They survive tabline toggles (bufferline appear/ disappear) — killed bars are recreated automatically. ============================================================================== 8. UI Layout *turbo-debug-layout* Default layout: Sidebar (|turbo-debug.setup.sidebar|, left or right, 25-40 cols): - Call Stack (25%) — current frames, navigate with `` - Scopes (25%) — local/global variables in current frame - Watches (25%) — user-added watch expressions (|W|) - Breakpoints (25%) — all persistent breakpoints, jump with `` Bottom pane (20% of editor lines, min 8 rows): - Console — program stdout/stderr + adapter output REPL is NOT in the default layout. Press `E` during debug mode to open it as a floating window on demand. Override the layout: >lua require("turbo-debug").setup({ dapui = { layouts = { ... }, -- see nvim-dap-ui docs for format }, }) < ============================================================================== 9. Adapters *turbo-debug.adapters* Built-in adapter support (adapter binary must be installed): Language Adapter Binary ~ Python debugpy python -m debugpy JavaScript/TS js-debug js-debug-adapter Go delve dlv C/C++ codelldb codelldb Rust codelldb codelldb Swift codelldb codelldb Zig codelldb codelldb Nim codelldb codelldb Crystal codelldb codelldb C# netcoredbg netcoredbg F# netcoredbg netcoredbg Java java-debug java-debug-adapter Kotlin kotlin-debug kotlin-debug-adapter PHP php-debug php-debug-adapter Ruby rdbg rdbg Dart dart-debug dart debug_adapter Flutter flutter-debug flutter debug_adapter Bash / Sh bash-debug bash-debug-adapter Elixir elixir-ls elixir-ls-debugger Haskell haskell-debug haskell-debug-adapter OCaml earlybird ocamlearlybird R vscDebugger R (with vscDebugger pkg) Lua (Neovim) osv one-small-step-for-vimkind Path resolution order: 1. User override via |turbo-debug.setup.adapters| 2. Binary on `$PATH` 3. Standard mason install path (~/.local/share/nvim/mason/bin/) Rust gets special treatment: pressing `c` runs `cargo build` automatically and picks the binary via `vim.ui.select` if multiple artifacts exist. Python auto-detects virtualenvs: `VIRTUAL_ENV`, `CONDA_PREFIX`, then the common directories `.venv`, `venv`, `env`, `.env` relative to `cwd`. Dart auto-detects Flutter: if `flutter` is on PATH alongside `dart`, a "Launch Flutter app" configuration is added to the `dart` filetype in addition to the plain Dart file launch. R requires the `vscDebugger` R package. turbo-debug preflights it via `Rscript` and silently skips registration if the package is missing. Install with `install.packages("vscDebugger")` or `remotes::install_github("ManuelHentschel/vscDebugger")`. Adapter binaries are the user's responsibility to install (mason.nvim is the easiest route). Override or add adapters: >lua require("turbo-debug").setup({ adapters = { python = { adapter = { ... }, configurations = { ... } }, zig = { adapter = { ... }, configurations = { ... } }, }, builtin_adapters = false, -- disable all built-ins }) < Existing user nvim-dap configurations are never overridden — if a user has already set `dap.adapters[name]` before `turbo-debug.setup()` runs, we skip it. ============================================================================== 10. API *turbo-debug-api* *turbo-debug.setup()* require("turbo-debug").setup({opts}) Initialize the plugin with optional configuration. Idempotent — safe to call multiple times; the last call's opts win. *turbo-debug.toggle()* require("turbo-debug").toggle() Toggle debug mode on/off. *turbo-debug.active()* require("turbo-debug").active() Returns `true` if debug mode is currently active, `false` otherwise. Useful for statusline integration. ============================================================================== 11. Troubleshooting *turbo-debug-troubleshooting* No adapter found ~ Ensure the adapter binary is installed and on your PATH, or installed via mason.nvim. turbo-debug configures adapters; it does not install them. Breakpoints not persisting ~ Check that persistent-breakpoints.nvim is loaded: >vim :lua print(require("persistent-breakpoints") and "ok") < Virtual text not appearing ~ Virtual text only appears during an active DAP session in debug mode. Ensure nvim-dap-virtual-text is loaded: >vim :lua print(require("nvim-dap-virtual-text") and "ok") < Bars look squished / have stray `~` markers ~ The bars auto-clamp to 2 rows on every resize event. If you see this persistently, please open an issue with your terminal and `:set lines? columns?` output. Version error ~ turbo-debug.nvim requires Neovim >= 0.12 for `vim.pack` support. ============================================================================== vim:tw=78:ts=8:ft=help:norl: