UI: theme, layout, hotkeys¶
The [ui] section configures the debugger window. It lives outside the profiles
because it has nothing to do with launching: a project has many profiles and one
window.
version = 1
[ui]
theme = "dark"
width = 1200
height = 800
[profiles.api]
adapter = "dlv"
program = "cmd/api"
| Field | Required | What it is |
|---|---|---|
theme |
no | dark (default), light or system |
width |
no | initial window width in logical pixels; 800 by default |
height |
no | initial window height in logical pixels; 600 by default |
layout |
no | panel layout, below |
keymaps |
no | window hotkeys, below |
Window size¶
width and height set the initial inner size of the native debugger window.
They are independent: omitting one dimension leaves that dimension to the
editor preference or the default. Values must be positive integers. Resizing
the window later does not rewrite the project config.
The precedence for each dimension is:
widthorheightin the project's[ui]section;gui_widthorgui_heightfrom the Neovim plugin;- the default:
800 × 600logical pixels.
The project value wins because it is shared by everyone opening the project.
Theme¶
The default is dark, not system. The debugger window opens next to your
editor rather than instead of it, and it should follow the OS setting only when
asked. That is what system is for, and with it the theme switches on a live
session.
An unknown value is a config parse error that lists the allowed ones — not a silent fallback to the default.
Silence is not the same as theme = "dark"¶
A theme named in [ui] beats everyone: it is shared by everyone who opens the
project. Not naming one leaves the choice to whoever opens the window.
Precedence:
[ui] themefrom the project config;--themefrom the editor (the plugin'sgui_themebecomesbugsaur gui --theme dark|light|system);- the debugger's default — dark.
A launch with no project (--adapter / --program) reads no config, leaving
only points 2 and 3.
Layout¶
The window is divided into a left column and a right area, each into two zones:
+----------------+-----------------------------+
| | |
| top_left | main |
| | |
+----------------+-----------------------------+ ← main_split
| | |
| bottom_left | bottom |
| | |
+----------------+-----------------------------+
↑ left_split ↑ left
| Field | What it is | Default |
|---|---|---|
left |
share of the window width for the left column | 0.25 |
left_split |
share of the column height for top_left |
0.35 |
main_split |
share of the right area's height for main |
0.35 |
top_left |
panels in the upper zone of the left column | ["Threads"] |
bottom_left |
panels in the lower zone of the left column | [] |
main |
panels in the main zone | everything else |
bottom |
panels in the zone below the main one | ["Call Stack"] |
Panel names are written exactly as their tabs read: Threads, Call Stack,
Variables, Watches, Evaluate, Logs, Inspector, Breakpoints. Panels in
one zone become a tab stack in the order listed.
[ui.layout]
left = 0.3
left_split = 0.5
top_left = ["Threads"]
bottom_left = ["Call Stack"]
main = ["Variables", "Watches", "Inspector"]
bottom = ["Evaluate", "Logs"]
A panel named in no zone is not shown — that is how panels are removed. An
empty zone takes up no space at all; an empty main gives its whole area to the
left column.
An unnamed zone keeps its default contents
Moving a panel therefore requires clearing its previous zone too:
main = [..., "Call Stack"] without bottom = [] is a "panel named twice"
error, not a silent choice between the two zones.
Also errors: an unknown panel name, a share outside 0 to 1, and a layout that leaves no panels at all.
Precedence works like the theme's, but the section is taken whole. If
[ui.layout] exists, it is used and the editor's gui_layout is not consulted
at all; if not, the editor's layout is taken whole (bugsaur gui --layout <json>,
same keys); if neither, the defaults above. Mixing zones from two sources would
assemble a window nobody designed.
Panels dragged with the mouse are not saved: the layout is built from the config on every launch.
Hotkeys¶
A dictionary of action → chord:
[ui.keymaps]
continue = "Alt+R"
step_into = "F3"
step_over = "F2"
step_out = "F5"
terminate = "Alt+S"
pause = "" # unbind
Actions:
- execution —
continue,step_into,step_over,step_out,pause,terminate,restart; - panels —
next_panel,previous_panel, and jumping to one:focus_threads,focus_call_stack,focus_variables,focus_watches,focus_evaluate,focus_logs,focus_inspector,focus_breakpoints; - navigation —
next_row,previous_row,top,bottom,collapse,expand,activate,delete_row,cancel; - search in Variables —
search,search_next,search_previous,search_continue; - other —
help.
An empty chord unbinds. TOML has no null, and there would otherwise be no
way for a config to remove a default. An action has exactly one chord:
focus_variables = "Alt+V" also removes Ctrl+V.
A chord is the modifiers Cmd, Ctrl, Alt, Shift joined by +, plus a key
name (F1…F20, a letter, Enter, Space, ArrowDown, …). Modifier order does
not matter. An unknown action, key or modifier stops the launch: a mistyped
hotkey would otherwise simply never fire, giving no sign of itself.
Precedence is per action, not per block. What [ui.keymaps] names overrides
gui_keymaps from Neovim; what it does not name stays as configured in the
editor; what nothing names keeps the built-in default. Per-block would be
awkward: bindings are independent of each other, and a project that overrides
continue alone should not wipe out someone's personal setup.
The full stack, bottom to top:
- built-in defaults (F7, F8, Shift+F8, F9, Cmd+F2 / Ctrl+F2, H J K L, the arrows);
<root>/.bugsaur-keys.json— a personal per-project file, chord → action, wherenullunbinds;gui_keymapsfrom the Neovim plugin'ssetup();[ui.keymaps]from this config.
F1 or ? in the window shows what all four layers produced.