Skip to content

Latest commit

 

History

History
196 lines (151 loc) · 7.19 KB

File metadata and controls

196 lines (151 loc) · 7.19 KB

Main Panel

The main panel owns the debugger UI windows, one scratch buffer per registered view, and the registration/lifecycle API consumed by the bundled views. Views never create their own windows or buffers; that boundary is CI-enforced by scripts/lint.lua.

Setup

require("nvim-dapper.panel.main").setup({
  placement = "bottom", -- "bottom" (default) | "right" | "float"
  height    = 15,       -- bottom default; rows (integer) or ratio in (0, 1)
  width     = 60,       -- right default; cols (integer) or ratio in (0, 1)
  auto_open = false,    -- open on session_started? off by default
  splits    = nil,      -- flat indexed split definitions; see below
})
  • placement: bottom, right, or float. Bottom sets winfixheight, right sets winfixwidth, and float is centered with a rounded border. Floats default to width = 0.6, height = 0.4.
  • height / width: positive numbers. Values in (0, 1) are ratios of the editor dimension; integers are absolute rows or columns.
  • auto_open: when true, session_started opens the panel if it is closed. Off by default.
  • splits: nil or a non-empty list of flat sibling split definitions.

Splits

Omitting splits creates one split containing all registered views in registration order. This is the default for require("nvim-dapper").setup({}).

Each configured split declares exactly one of:

{ view = "console" }
{ views = { "variables", "stack", "watches" } }

view is shorthand for a one-entry views list. View ids may be configured before views are registered; resolution happens when the panel opens. If an id is still unregistered at open time, panel.open() raises and leaves the panel closed.

Duplicate ids, empty views, non-string ids, unknown split keys, and legacy layout / panes options raise during setup. View registrations must not include pane or split ownership fields; layout assignment belongs in panel.splits.

Size Grammar

Each split may set size:

splits = {
  { view = "variables", size = "45%" },
  { view = "console", size = 30 },
  { view = "stack" },
}
  • size = 30 means 30 cells along the split orientation.
  • size = "45%" means 45 percent of the available panel dimension.
  • omitted sizes divide the remaining cells evenly.

Numeric ratios such as 0.45, non-integer numbers, zero, negative numbers, and malformed percent strings are rejected. If resolved sizes cannot fit when the panel opens, the call raises and closes any panel windows it created.

Orientation

Wide placements, bottom and float, arrange splits left-to-right. Tall placements, currently right, arrange splits top-to-bottom.

Debug Statusline

Every open panel split receives a window-local statusline, replacing the default scratch-buffer presentation. Exactly one split is the debug status carrier:

  • wide layouts (bottom and float) use the leftmost split;
  • tall layouts (right) use the bottom-most split.

The carrier renders require("nvim-dapper.session").current_status() with a compact format:

IDLE
● RUNNING | Profile: Remote-Docker (✈ 192.168.1.50)
⏸ PAUSED @ auth.js:18 | Profile: Remote-Docker
✕ STOPPED | Profile: Remote-Docker

Profile metadata is shown as Profile: <name>. When a process or target hint is available, it is rendered after the profile in parentheses, preferring PID: <pid> over ✈ <connection> over target text. Non-carrier splits use a single-space local statusline so they render blank instead of falling back to the user's global statusline. The carrier uses DapperPanelActiveView, the same highlight group used by the active view label in the winbar.

The panel refreshes all split statuslines after panel open, view lifecycle changes, and synchronously when the panel's main-panel session subscription receives a session event. Winbars remain split-scoped and continue to own view switching and active-view highlighting.

View Registration

local panel = require("nvim-dapper.panel.main")

panel.register_view({
  id   = "variables",
  name = "Variables",
  render = function(buf, ctx) ... end,
  on_mount   = function(buf, ctx) ... end,
  on_unmount = function(buf, ctx) ... end,
  on_focus   = function(buf, ctx) ... end,
  on_blur    = function(buf, ctx) ... end,
  on_session_event = function(buf, event, ctx) ... end,
})

Required fields are id, name, and render. Duplicate ids raise. Registration order is preserved globally for panel.list_views(), :DebugView completion, and session-event fan-out.

Lifecycle

Views are mounted on first activation, never at registration:

nvim_create_buf -> on_mount -> render -> nvim_win_set_buf -> on_focus

Switching within a split blurs the outgoing active view, mounts or refreshes the incoming view, swaps the buffer with nvim_win_set_buf, updates that split's winbar, then focuses the incoming view. Scratch buffers remain valid across switches and panel close/open.

ctx is allocated once per view and reused across callbacks:

{ panel = panel, view_id = "variables", win = win_or_nil, session = session, split_id = 1 }

ctx.win is the active split window while the view is focused and is cleared after on_blur. ctx.split_id identifies the active split during lifecycle callbacks.

Programmatic API

Function Purpose
panel.open([target_id]) Open all configured splits; mounts target view first when provided.
panel.close() Close every split window. Buffers and view state are retained.
panel.toggle() open if closed, close if open.
panel.show_view(id) Switch the owning split to id; opens the panel if closed.
`panel.cycle_view("next" "prev")`
panel.request_redraw(view_id) Re-render now if active, mark dirty if inactive, no-op if unmounted.
panel.current_view() Focused split's active id, fallback to split 1 while open, or nil.
panel.split_view(index) Active view id for a 1-based split index, or nil.
panel.is_open() true if any owned split window is valid.
panel.get_win() Focused split window, split 1 fallback, or nil.
panel.split_win(index) Window handle for a 1-based split index, or nil.
panel.list_views([index]) Fresh global view order, or a split-scoped view order.

Session Events

The panel subscribes to the session manager once under subscriber_id = "main-panel" and fans every event out to mounted views in global registration order. Unmounted views do not receive events because they do not yet have scratch buffers.

Commands

Command Behaviour
:DebugPanel Open the panel; focuses it if already open.
:DebugPanelToggle Toggle open/closed.
:DebugPanelClose Close the panel.
:DebugView <id> Switch to a registered view id.

Winbar

Each split window renders a split-scoped winbar. Active segments use DapperPanelActiveView; inactive segments use DapperPanelInactiveView. Defaults are installed with:

hi default link DapperPanelActiveView   Title
hi default link DapperPanelInactiveView Comment

Segments use Neovim statusline click regions and route through require("nvim-dapper.panel.main")._winbar_click.