Glyph fonts: renderable trim indicators, and vertical metrics on IGlyphFont - #68
Merged
Merged
Conversation
…yphFont`. A FIGlet-trimmed line could render its trim indicator as nothing at all: no bundled face has a glyph for U+2026, and the formatter budgeted for an ellipsis the face could not draw. `IGlyphFont.HasGlyph(uint)` is a default interface member so external implementors stay source-compatible, and honest for pass-through faces that hand the cluster to the terminal. `ShadowedFont` and `DecoratedFont` forward to `Inner` — inheriting the optimistic default would silently reinstate the bug behind any decorator. `TextFormatter` now chooses the indicator per face: the configured `Ellipsis` if the face can draw every codepoint of it, else `"..."`, else the configured ellipsis re-sourced to `GlyphSource.Default` so the terminal's own font draws it. A mismatched indicator is a defect in taste; an invisible one is a defect in correctness. `U+2026` art is authored for eight bundled faces; `miniwi` and `phm-leds` ship a truncated required block, whose positional layout would be corrupted by an appended codetag, so they fall back to the derived form. That last-resort path then exposed a second defect. Runs align to the band's BOTTOM row, so a one-cell indicator beside a multi-row face landed in the DESCENDER row — one row low on standard/small/mini/slant, two on big. It was invisible until now because a band whose runs share one face shares their metrics, and the mixed-source fallback is the first construct that does not. So `IGlyphFont` gains `Baseline`, `Ascender` and `Descender`, parsed from FLF header field 1. `Baseline` is a COUNT of rows from the top through the baseline row, never a 0-based index — the index reading renders correctly on ansi-shadow (7/7) and wrong on every other face, so both the contract and the tests name the distinction explicitly. `VerticalTextAlignment.Baseline` is declared last, so `default` remains `Bottom`, and only the last-resort indicator opts into it. The decorators are not pure forwards here, and the painting code decides it: `ShadowedFont` paints the glyph at the caller's anchor and the shadow below, so its baseline is `Inner`'s and only its descent grows; `DecoratedFont` shifts the baseline down for `Above` and deepens the descent for `Below`. All three bundled `DecoratedFont` instances wrap `MonospaceFont`, where every reading agrees — so no shipped configuration could have caught it. Rendering 679, UI 3509, Drawing 460 — all green. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A4i5CZSjkU1TbAgiYBomhL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A FIGlet-trimmed line could render its trim indicator as nothing at all — no bundled face has a glyph for
U+2026, and the formatter budgeted for an ellipsis the face could not draw. Fixing that exposed a second defect underneath it.Renderable trim indicators
IGlyphFont.HasGlyph(uint)is a default interface member, so external implementors stay source-compatible.ShadowedFontandDecoratedFontforward toInner— inheriting the optimistic default would silently reinstate the bug behind any decorator.TextFormatterpicks the indicator per face: the configuredEllipsisif the face can draw it, else"...", else the ellipsis re-sourced toGlyphSource.Defaultso the terminal's own font draws it. A mismatched indicator is a defect in taste; an invisible one is a defect in correctness.U+2026art is authored for eight bundled faces.miniwiandphm-ledsship a truncated required block whose positional layout an appended codetag would corrupt, so they use the derived form, guarded by two table-integrity tests.Vertical metrics — the defect the fallback created
Runs align to the band's
Bottomrow, so a one-cell indicator beside a multi-row face landed in the descender row — one row low on standard/small/mini/slant, two on big. Invisible until now because a band whose runs share one face shares their metrics; the mixed-source fallback is the first construct that doesn't.IGlyphFontgainsBaseline,Ascender,Descender, parsed from FLF header field 1.VerticalTextAlignment.Baselineis declared last sodefaultstaysBottom; only the last-resort indicator opts in.The decorators are not pure forwards
ShadowedFontInner's, unchanged (glyph at the anchor, shadow below)DecoratedFontAboveDecoratedFontBelowAll three bundled
DecoratedFontinstances wrapMonospaceFont, where a single-row inner face makes every reading agree — no shipped configuration could have caught this, so it was derived from the painting code rather than from behaviour.Two pre-existing quirks were found, documented in
<remarks>, and left alone:ShadowedFontwith a negative row offset paints outside the boxMeasurereports, andDecoratedFontdraws aBelowdecoration at a hard-codedrow + 1.Verification
Red-first: the fallback test failed
Expected: [4] / Actual: [5]on a 6/5 face — the descender row exactly.Rendering 689 (+51) · UI 3521 · Drawing 484 · Core 1071 — all green, re-run after rebasing onto
develop.🤖 Generated with Claude Code
https://claude.ai/code/session_01A4i5CZSjkU1TbAgiYBomhL