Three fixes to bar rendering:
- The "terminate_____" trailing underscores were TurboDebugBarKey
(bold+underline) bleeding from a misaligned extmark. The old code set
the key-hint extmark starting at `right_byte_start + 1` — 1 byte INTO
the 4-byte help emoji — spanning 4 bytes across the emoji boundary.
When 💡 (U+1F4A1) didn't render as a glyph in the user's font, the
underline still rendered on those cells: producing visible underscores
in empty space. Drop the key-hint extmark on the help label entirely.
The emoji (if rendered) is already the visual; underline isn't needed.
- Restart icon ♻️ (U+267B + VS16) switched to 🔄 (U+1F504). VS16 forces
emoji presentation only when the font HAS an emoji glyph for that
codepoint — many don't, leaving text-mode rendering or blank. 🔄 is
supplementary-plane so it always renders as color emoji regardless.
- REPL pane title: dropped 💬 icon per user preference. Title is now
just " REPL" — the prompt format `dap>` is already a clear visual
differentiator, no need for a chrome icon.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Control bar refinements:
- All-emoji icons, supplementary plane only (plus ♻️ with VS16 per user
preference). Dropped Nerd Font Codicons — they rendered as unrelated
glyphs in the user's font (debug-start as a gear, step-into arrow
backwards, etc.). Replaced set:
🚀 start / 🟢 continue (dynamic), 👣 step over, 🔽 descend,
🔼 return, ♻️ restart, 🛑 quit/terminate, 💡 help.
- Modal label text — the tail after the (key) updates based on dap state:
no session: "(c) start" / "(q)uit"
active: "(c)ontinue" / "(q) terminate"
So the label always shows what pressing the key will actually do.
- Help icon switched from ❓ to 💡 — ❓ (U+2753) was rendering zero-width
in the user's font so the help label effectively disappeared. 💡 is
supplementary-plane and renders reliably.
Launch picker focus fix:
- run_in_source() now calls nvim_set_current_win instead of nvim_win_call.
nvim_win_call returns focus to the caller's window synchronously, so
when dap.continue() triggered an async vim.ui.select picker, the picker
opened but no window held focus — user had to click into it manually.
Shifting focus directly means the picker inherits source-window focus.
Bar buffer robustness:
- buftype=nofile + BufEnter autocmd that bounces focus back if anything
accidentally lands in the bar. Prevents E21 "Cannot make changes,
'modifiable' is off" that the user hit after a mouse drag landed focus
in the bar and their next keypress tried to edit.
dapui pane gutter cleanup:
- set_dapui_window_opts now forces number=false, relativenumber=false,
signcolumn=no, statuscolumn="", foldcolumn=0, and sets fillchars=eob:
to hide the `~` end-of-buffer marks. snacks statuscolumn was rendering
a gutter with line-number-like marks in dapui panes where they have no
semantic meaning.
Sidebar reorder from last commit stands: Call Stack → Scopes → Watches
→ Breakpoints.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Control bar — design overhaul per UX feedback:
- 3 zones: state chip (left), controls (centered), help (right). Each zone
gets a dynamic-width spacer between. As the window narrows, drop first
dap.status(), then controls (text collapses), then chip detail — help is
NEVER sacrificed per user priority.
- Control icons are all Nerd Font Codicons now ( ).
Mixed emoji + VS16-text combinations were rendering inconsistently in
the user's font (▶️⬇️ as text-mode glyphs while 🔴🐛 rendered as emoji).
Codicons all ship in the same Nerd Font range → uniform look.
- Help label drops the redundant "(?)" — the ❓ emoji is self-documenting.
Now reads "❓ help" instead of "❓ (?) help".
- Key letter (the s in (s)tep, etc.) gets bold + underline + Special's fg
via a derived highlight (nvim_set_hl can't combine link + bold attrs).
Re-applied on ColorScheme so theme swaps don't lose the styling.
Sidebar reorder — ergonomic over convention:
- New order: Call Stack, Scopes, Watches, Breakpoints (was Scopes first).
- When paused, the first question is "where am I?" → Call Stack first.
- Call Stack adjacent to Scopes means clicking a frame updates the Scopes
right below it — visual affordance for the Call-Stack-drives-Scopes
relationship. VS Code puts Scopes first; IntelliJ/Xcode put Frames
first. We side with the ergonomic argument over convention.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The symptom: pressing c in dapui_scopes/watches/stacks/breakpoints/console
printed "No configuration found for dapui_<pane>" because nvim-dap looks
up dap.configurations[vim.bo.filetype] from the current window — and in
dapui panes that filetype is dapui_* (no configs), not the source file's
filetype.
The modal key WAS firing; our smart_continue() ran but then ended up
calling dap.continue() from the dapui pane's context, which blew up on
config lookup.
Fix: wrap the launch in run_in_source() which finds a window whose
filetype isn't dapui_*/dap-repl/TurboDebugBar, then nvim_win_call()s
into that window so nvim-dap reads the real source filetype (rust,
python, go, etc.). Post-session dap.continue() resumes work as normal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
UX refinement per design feedback:
- Bar is now 3 rows tall: ─ top separator, content row, ─ bottom separator.
The separator chars were invisible before because TurboDebugBarSeparator
linked to WinSeparator (muted in most themes). Switched to FloatBorder.
- Bottom tray default shrunk 12→9 rows so the 3-row bar doesn't overlap
REPL/Console. Net vertical footprint unchanged (12 tray = 9 tray + 3 bar).
- Action labels now teach the keyboard shortcut inline:
▶️ (c)ontinue ⏭️ (s)tep ⬇️ (d)escend ⬆️ (r)eturn
🔄 (R)estart 🛑 (q)uit ❓ (?)help
The (k) letter is highlighted with TurboDebugBarKey → Special so the
shortcut pops. The entire label is a click zone.
- help_on_enter default flipped true → false. The (?)help label in the bar
is always visible, so new users discover help via the bar instead of an
auto-popup on every debug-mode entry.
- No top bar added. The source file winbar already shows 🐛 DEBUG · <file>,
so a second chrome row would just duplicate context and eat screen space.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses live-feedback issues that persisted after v3:
- Control bar now uses buffer content + extmarks instead of winbar —
winbar doesn't render in minimal-style floats, which is why the bar
was empty. Two rows: ─ separator on top, state chip + controls below.
Click dispatch via buffer-local <LeftMouse> keymap + cursor-column
lookup against a zones table.
- Bar auto-refreshes on every dap event (initialized/stopped/continued/
terminated/exited) so the READY/RUNNING/PAUSED chip and dap.status()
text stay live.
- Colorful emoji throughout for instant recognition:
Signs: 🔴 BP, 🟡 conditional, ⭕ rejected, 👉 stopped, 📝 logpoint
Titles: 🔎 Scopes, 👁️ Watches, 📚 Call Stack, 🔴 Breakpoints,
💻 Console, 💬 REPL
Badge: 🐛 DEBUG · <file>
Controls: ▶️⏭️⬇️⬆️🔄🛑❌
- Modal key install no longer skips buffers that already have entries —
every BufEnter/FileType force-reinstalls the keymaps so dapui's own
render pass can't leave them in a broken state.
- IP sign leak fixed: clear_ip() now unplaces lingering DapStopped signs
via sign_getplaced + sign_unplace, so restart no longer leaves a stale
👉 in the gutter of the previously-paused line.
- IP reason text (STEP/BREAKPOINT/EXCEPTION) now uses bold + reverse for
an inverted-color badge that really demands attention.
- dapui.expand_lines = false — this was spawning a cursor-pinned float
when a line was wider than its pane, causing the "hover text bleeds
across the screen" bug. With wrap+breakindent inside the pane, the
hover-float is redundant and destructive.
- Control-bar buffer is marked filetype=TurboDebugBar and explicitly
skipped by the modal key installer, so clicking a button doesn't
accidentally fire modal actions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major v3 fixes driven by live-debugging feedback:
- Control bar: replace vim.o.statusline override (lualine fights it) with
a 1-row floating window pinned above the statusline. Shows state chip
(READY/RUNNING/PAUSED) + seven clickable Codicon controls + dap.status().
Survives resize via VimResized autocmd. Fully independent of lualine.
- Console refresh: trailing-edge throttle at config.console_refresh_ms
(default 50ms = 20 Hz ceiling). Targets console windows via nvim_win_call
+ redraw! to avoid screen-cache miss. Chatty programs can't DOS the editor.
- Modal keys in dapui panes: install synchronously on FileType (drop inner
vim.schedule); all modal keys get nowait=true (was continue-only) so
single-key presses aren't swallowed by <leader>d* prefix matching.
- Wrap in dapui panes: wrap=true + breakindent + showbreak=" ↳ " so long
register values stay visible inside the pane without bleeding into the
source window. Safety valve at config.max_value_width (default 2000,
set 0 to disable) truncates only pathological multi-KB dumps with "…".
- Smart q: context-aware terminate. If a session is running, q calls
dap.terminate() and stays in debug mode (so user can read the console
postmortem). If no session, q exits debug mode. Removes quit_exits_mode.
- Icons: full Nerd Font Codicon set for signs, control bar buttons, pane
titles, and debug badge. 👈 emoji in the paused-line vtext pairs with
👉 in the gutter — fingers literally point at the paused line from both
sides.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename from tiny-debugger to turbo-debug — inspired by Turbo Pascal,
the first IDE with a real visual debugger. This thing isn't tiny,
it's turbo charged.
CHANGELOG for 0.1.0:
Features:
- Zero-config debugging — one line install, everything works
- Modal keybindings (c/s/d/r/q/x/X/D/W/K/E/R/?), active only
during debug mode, cleanly removed on exit
- Persistent breakpoints via persistent-breakpoints.nvim
- Inline virtual text — variable values in source code
- Hover (K), watch (W), REPL eval (E) from the code window
- Help splash (3s auto-dismiss) + manual help (?)
- Debug mode chrome — winbar indicator, cursor highlight
- dapui integration — controls toolbar, labeled panels
- which-key support — <leader>d debug group auto-registered
- quit_exits_mode option
Adapters (12 languages):
- Python (debugpy + venv detection)
- Rust (codelldb + cargo build + vim.ui.select picker)
- Go (delve), C/C++/Swift (codelldb)
- JavaScript/TypeScript (js-debug-adapter)
- C# (netcoredbg), Java, Kotlin, PHP, Ruby, Lua (osv)
Keybindings:
- <leader>dd — toggle debug mode
- <leader>dx / <leader>dX / <leader>dD — breakpoints (always)
- c s d r C x X D W K E q R ? — modal (debug mode only)