Font, licence, and the metrics half of Tier 3.
The bundled font is Latin Modern Math under the GUST Font License, added as
fonts/GUST-FONT-LICENSE.txt — deliberately a separate file from fonts/OFL.txt,
which covers JetBrains Mono only. GFL is LPPL-derived, not the SIL OFL; the
framing's F6 corrected that error and this is the discharge. At 733,736 bytes
the font is now the largest embedded asset in the repository.
ttf-parser is declared with default-features = false and only
"opentype-layout". Verified differentially: the ttf-parser feature set from
`cargo tree -e features` is byte-identical with and without this dependency
line, so the declaration widens nothing and forces no rebuild of the font
chain.
That check also corrected acceptance 17, which asserted `std` would be absent.
It is not — fontdb already enables it via `std = ["ttf-parser/std"]`, upstream
and independent of us. As written the criterion would have failed a correct
implementation, so it is now stated as the differential property that actually
matters.
MathConstants reads only what the Q#MS2 subset needs — axis height, script
scale percent, the two script shifts, and fraction rule thickness. Reading
more would be speculative: constants for deferred constructs have no consumer
to validate them, which is the Q#LX5 discipline applied to metrics. A font
with no MATH table is a typed error rather than plausible-looking zeros, so a
bundled-font regression cannot be silent (Q#MS7).
math_italic implements TeX's convention as the framing's table states it:
ASCII letters and lowercase Greek italic, uppercase Greek upright, digits and
operators unchanged, with U+210E for `h` because the 1D4xx run has a hole
there and arithmetic would land on a reserved codepoint.
Five tests, all against the real embedded bytes rather than fixtures, since B5
is the bet that would sink Tier 3 if false. One goes beyond the framing: every
italic mapping must resolve to a glyph the bundled font actually has, because
a mapping that produced tofu would be worse than the roman fallback it
replaces.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Normalize source bytes to representable shaped-cluster cursors and
reflow the code buffer whenever gutter or minimap geometry changes.
Measure alternate monospace advances across complete shaped runs and
load hermetic fixture faces before FontSystem construction. Complete
the rendered geometry, popup, caret, snapshot, and fixture acceptance
coverage, and record the review fixes in framing revision 5.
Twenty-one new headless tests covering the GPU-side acceptance items of
docs/gpu-set-font-framing.md (9-14, 16-19):
- 9: size route re-derives metrics; (None, None) reset reproduces
the never-set frame byte-for-byte
- 10: 600/7200 bounds render; minibuffer dropdown windows its rows
above the band at the derived row height; context menu keeps
the clipped route with coherent hit geometry
- 11: wrapped caret survives 16->72->6 px; an optimistic insertion
that wraps a new bottom row follows immediately and its
confirming CursorByte needs no second repair; overscan caret
never snaps the viewport; narrowing resize re-follows via the
coarse + visual-run + fold pipeline; adornment projection
shifts the caret past injected text with left gravity at the
anchor; the CursorByte arm follows into a wrapped run as a
normalized sub-line residual; explicit scrolls clear the
residual (including wheel-up at the clamp edge); the
minibuffer suspends the follow decision
- 4 (GPU half): BufferSnapshot resets the residual while the font
preference/metrics survive -- the replacement buffer wraps
too, so the EOF clamp cannot mask a leaked residual
- 12: unknown + proportional families fall back; the four-style
gate rejects a proportional BOLD sibling the normal-only
query would accept; a valid second monospace family resolves,
changes the ink, and resets cleanly; the parameterized
sanitizer removes exactly the same-family proportional
collision
- 13: the "\0" sentinel defeats the status string-equality gates
- 14: a shrinking visible slice re-declares the scoped viewport
- 16: 0/599/7201/u32::MAX reject the whole message, state untouched
- 17: metrics + drawable dimensions atomic on all seven buffers,
resize symmetric via Buffer::size()
- 18: popup rows never wrap (Wrap::None + unique line_i per run)
- 19: with line numbers and a context menu open over an EMPTY
buffer, the measured probe advance drives gutter reservation
and menu hit width (fixture ratio exactly 1.2 vs the bundled
default); reset restores the exact geometry and frame
Family routing is hermetic: four generated fixture faces under
pmacs-gpu/fonts/test/ (second monospace at 720/1000, a proportional,
and a "Pmacs Test Family" whose NORMAL face is monospaced but whose
BOLD face is proportional), built by the committed generate.py --
provenance and license in LICENSE.txt beside them. fontdb requires a
PostScript name (nameID 6), which the generator sets explicitly.
assemble() now routes construction through sync_buffer_dimensions
too: shape_until_cursor and wrapping must use the painter's clip
from the first frame -- a v16 daemon never sends the FontFacts that
would sync them later (found by the CursorByte-follow test: the
caret parked in the status band at surface-height dims).
Every protection was bitten (temporarily reverted, its test observed
failing, then restored): wire validation, CursorByte visual-run
follow, painted-before gate, projection inversion, Wrap::None,
four-style gate, sanitizer, status sentinel, normalize fold,
scroll_by_lines residual clear, BufferSnapshot residual reset, the
all-seven dimension helper, and the optimistic-completion follow.
The snapshot-reset test was strengthened after its first bite did
NOT fail (a short replacement buffer let cosmic's EOF clamp zero the
residual anyway).
PMACS_REQUIRE_GPU suite 90/90; clippy -D warnings and fmt clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoiEyuPjoBhvwACf8HAnLB
Adds the pmacs-gpu binary crate to the workspace. wgpu 29.0 + winit
0.30 + glyphon 0.11 (cosmic-text 0.18 via re-export) + pollster +
env_logger; pmacs-protocol in the dep graph but not consumed yet
(session 3 wires the attach loop).
The binary opens an 800x200 window titled 'pmacs-gpu hello-world',
sets up wgpu against its surface, configures glyphon with the bundled
JetBrains Mono Regular, and renders 'hello, pmacs' once per redraw.
Close button or Escape exits. Resize re-configures the surface and
glyphon viewport. Surface acquisition matches wgpu 29's
CurrentSurfaceTexture enum (success/suboptimal render through; lost/
outdated re-configure; timeout/occluded skip the frame).
Bundled assets: pmacs-gpu/fonts/JetBrainsMono-Regular.ttf (268 KB)
and pmacs-gpu/fonts/OFL.txt. Font shipped as required by the SIL
Open Font License 1.1.
One finding surfaced during the move and absorbed under rule (iii)
of the framing pass (small / no structural change): the design doc
recorded JetBrains Mono as Apache 2.0; the actual license has been
OFL since the family's open-source release. Doc corrected in
docs/pmacs-gpu-design.md.
Gates: cargo fmt + cargo clippy --all-targets -D warnings clean for
the whole workspace; cargo test --lib still 1314 (pmacs main crate
untouched); m4_acceptance 83; m11_5_semantic_acceptance --features
crdt 2.
Visual confirmation pending — agent environment is headless, so
'window opens, text renders' is user-side validation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>