2 — How a dropped file becomes a picture
Written: 2026-08-15 · Established by: reading src/parser/index.ts, src/parser/tokenizer.ts,
src/parser/interpreter.ts, src/checks/index.ts and src/store/file-slice.ts at commit 93a9a67.
This is the path everything else hangs off. A file arrives, parseGCode turns its text into a
GCodeFile, the store holds that one object, and the viewer and the sidebar are both projections of
it. Nothing is cached between the text and the picture, so re-parsing is how every later change lands
too — see diagram 4.
Intake and fan-out. The store holds one GCodeFile, and three surfaces are projections of it.
Inside parseGCode. tokenize is the only stage that reads the raw text; every other stage reads
blocks, and three of them read the interpreted moves as well.
The order in parseGCode is the contract
tokenize is the only thing that reads the raw text. Everything downstream reads GCodeBlock[], and
three of the six stages read the interpreted Move[] as well. That split is why a check can report a
line number without re-lexing, and why src/transforms/apply.ts can splice text back by block index.
interpretBlocks is where the program is actually executed. It carries modal state, expands
subprogram calls and canned cycles, and returns the four things the rest of the parse needs: the
moves, the block index it halted at if it could not continue, the calls whose expansion hit the cap,
and the cycle it declined. Those last three exist so runChecks can report a limit as a finding
rather than the parser failing silently.
Halting is normal and partial. haltedAtBlockIndex is a real state a production file reaches —
issues #291, #293 and #296 are all programs that halt on a construct Ranger does not yet interpret.
The moves found before the halt are still drawn.
Two invariants this path enforces that the diagram cannot show
Position known-ness is per axis. A move that commands an axis never established is kept with
fromAssumed: true rather than dropped, and anything turning moves into geometry, bounds or a count
of real motion filters on isDrawable — ADR-0016.
Units are 'mm' | 'inch' | null, and null is not millimetres —
ADR-0021. detectUnits returns the
third value for a program that declares neither, which is a program that runs in whatever the control
was left in.
Where the second entry point is
safeParseGCode in src/parser/index.ts wraps the same call in a try. The store's loadFile has its
own private tryParse doing the same thing, because a caller outside the store — a second file picked
for comparison in src/compare/ — has no undo history to fall back on if the parse throws.