Skip to content

Variables

The Variables panel shows everything in scope in the selected stack frame, as a tree. Ctrl+V opens it, and focus starts here when the window opens.

Reading the tree

The top level is the scopes the adapter reports — Locals, Arguments, globals, and whatever else the language has. Below each one are its variables; below a structured variable, its fields.

When Locals is the only scope and the adapter does not mark it as expensive, the redundant Locals row is omitted: its variables appear directly at the top level and are loaded automatically. With multiple scopes, or with an expensive scope, the scope headers remain visible and collapsed as usual.

Keys Effect
J / K, Down / Up move the selection
L / Right expand a node
H / Left collapse a node
Enter / Space toggle the node
G / Shift+G first / last row

Colour means the kind of value

Colour is not about importance — it tells you what you are looking at:

Colour Kind
Green string
Blue number, boolean
Dimmed nil / null / None
Grey in braces the type name

/ opens a search line at the bottom of the panel. Matches are found as you type and the selection jumps to the nearest one below the row you started from, wrapping at the end. Enter ends the input; after it N and Shift+N walk forwards and backwards through the matches, and the counter on the right says where you are — 3/17. Esc drops the search.

Where it looks the variable name only; neither the value nor the type is searched
Case a lowercase query ignores case, any capital letter makes it exact
Matching plain substring — not a regular expression, not fuzzy

The search reaches into structures you have not opened. A field inside a collapsed node is found by its name, and jumping to it expands the path down to it. What the adapter has not sent yet is fetched by the search itself: while you type, the window walks the tree and asks for the nodes it is missing, shallowest first, so the counter keeps growing as answers arrive. scanning next to the counter means that is still happening — and while it does, an empty result is never reported as no matches, because not finding something and not having looked yet are different answers.

Whatever the adapter has sent stays searchable until the program moves again, whether the node is collapsed or not.

Nodes the search opened stay open after Esc: getting you there is what it was for. The search itself survives stepping — the query and the highlight stay, matches are recomputed against the new stop, and the selection returns to the same field. That is the point: find a field, then press F8 and watch its value change without retyping anything.

Limit Value What it does
Matches shown 10 the list is cut here, and the crawl stops with it
Nodes 2000 the crawl stops after asking the adapter for this many nodes
Depth 12 levels anything deeper is never queued
Requests per batch 32 paces the adapter; stops nothing
Typing pause 500 ms how long the query must hold still before it is recomputed
Elements per container 100 the first page of an array, not the whole of it

The first three stop the search, joined by or — whichever comes first wins. partial appears whenever something was left out: more matches than fit, or tree left unwalked. If everything ran out first you get a plain counter, or no matches.

The match limit is a limit on the list, not on the crawl. One fetched node arrives with all its children at once, so a limit that only stopped the crawl would turn a promised ten results into a hundred. The list is cut at ten, and what is beyond it is reported rather than shown.

Ctrl+/ shows one more portion — ten more matches — and grants the crawl another 2000 nodes and 12 levels to find them. It raises the ceilings rather than removing them, and the crawl resumes where it stopped: no node is ever asked for twice in one stop. Editing the query returns the limit to ten: a different query is a different search, and the portion you asked for does not carry over to it.

The match limit only bites when there is plenty to match. A query that matches little is stopped by the node or depth limit instead, which is why a narrow search can walk a long way before it says partial. The two guard opposite mistakes: ten matches against too broad a query, 2000 nodes against too narrow one. Together they are what keeps a cyclic or effectively infinite object graph from turning / into an endless stream of requests.

Matches are recomputed once your typing pauses, not on every keystroke — a fast typist would otherwise pay for every intermediate query they never meant to search for. The pause is counted from the last key you pressed, so typing a long name straight through costs exactly one recomputation. Enter does not wait.

A new stop resets all of it: everything asked for, every budget, every Ctrl+/ you granted. The search itself survives — the query and the highlight stay.

What you see

Every matching row is tinted, and the matched part of the name is highlighted inside it, so it is clear why a row is in the list. The current match is the selected row — there is no second kind of selection to keep track of. The value is never highlighted: the search does not look there, and a highlight would promise a match where none was sought.

Loading is lazy, on purpose

A collapsed node makes no request. Expanding one is what fetches its children, and only its immediate children — the object graph is never walked recursively. The only exception is the single inexpensive Locals scope described above: its immediate children are requested automatically because its header is not shown.

Large collections are paginated rather than fetched whole. A hundred-thousand element array does not arrive in one response and does not freeze the window; you get a page at a time as you scroll.

This matters in practice: it is why expanding a big structure is fast, and why a value can take a moment to appear the first time you open it.

Values are read at the stop they belong to

Everything the panel shows is cached against the current stop. When the program moves — a step, a continue, a new breakpoint — the cache is dropped and the tree is rebuilt from the new state. Answers that arrive late, after the program has already moved on, are discarded rather than shown: a value from the previous stop displayed next to the current line would be worse than no value at all.

Truncated and oversized values

Adapters cut long values off. When that happens the row shows what arrived, and the Inspector panel — Ctrl+I — shows the full value for the selected row, says explicitly when the adapter truncated it, and offers copying and JSON formatting.

Nothing is shown

If the tree is empty while the program is stopped, check the Call Stack: a frame with no debug information has no scopes to report. That is normal for optimised or third-party code, and for a Rust or C/C++ binary built in release mode.