`i' on a local sent the local's *name* to be evaluated, and an expression is evaluated where the evaluator stands. That is the right frame only when the frame is the innermost one; on any other it may resolve to a global, to another binding of the same name, or to nothing, with the locals listing right above it showing the frame's own storage and nothing saying the two disagree. The daemon verb for the fix landed already. What was missing was the state layer under it: `flan-inspect--expr' held a bare expression, so there was nowhere to put a frame. It is `flan-inspect--root' and `flan-inspect--path' now — `(:expr E)' or `(:slot FRAME SLOT NAME)', plus the steps walked from it — and a stack entry is `(ROOT PATH . POINT)'. RET appends a step, `l' restores a pair it pushed. Every step is still a fresh request, so the view is never stale. `l' cannot cross between the two roots, and that is structural rather than a rule someone has to keep: RET only ever extends the path under the root the buffer already has, and `flan-inspect' and `flan-inspect-slot' both start with an empty stack, so a mixed stack cannot be built at all. It stays true if a third rooting mode is added. The break buffer hands over the frame and the slot *index*, which is the fourth element `locals' now puts on each line. A name does not identify a slot: two slots of one frame can share one, and a refused slot is not in the listing, so its position is not an identifier either. A global still goes in by name, because a global's name really is an expression that means the same thing wherever it is evaluated — the loaded thunk binds to the program's own storage through the dynamic linker. Two smaller things the wire needed. A field step carries the type it was read out of, because a union's payload is at an offset that depends on the case and only the renderer knows which case the value is in — so `Union.case.field', which is the head the renderer wrote with the field appended. And an empty path is sent by omission: Emacs prints an empty list as `nil', which is a symbol on the wire, so the daemon now reads that as no path rather than refusing it as a step.
Description
Languages
OCaml
67.2%
Emacs Lisp
15.2%
C
10.4%
HTML
2.9%
Standard ML
2.8%
Other
1.5%