The sheet quotes the row's cut instead of guessing at it - #618
Merged
Conversation
Typing "Crossbowww" showed all ten letters in the editor, under a warning saying the name would be cut, and saved to a row reading "Crossbow…". The field drew the name at 17pt in a box `nameMaxWidth × 17/12` wide and truncated it there, on the theory that enlarging both sides of the ratio keeps the ellipsis on the same character. It does not. A line is `size × Σ(advances) + (count − 1) × tracking(size)`, and SF's tracking table is per-size, so 17pt type is proportionally narrower than the ratio predicts and the field is systematically the more generous of the two. Over 1,296 names the two cuts differed 597 times — half of them — always with the field keeping a character the row drops. "Crossbowww" is 74.63pt against a 71.75pt column and 101.40pt against a 101.65pt field: cut on one surface, fitting on the other, by a quarter of a point. No width formula fixes this. Scaling by the measured ratio of the same string at both sizes gets 597 down to 35, and with the ellipsis included to 29; each is still a second truncation asked to agree with the first by arithmetic. So the second truncation goes. `NameTruncation` resolves the row's own visible text once, at the row's font, size and column, and the field draws that string. There is one answer, so there is nothing to disagree. `isNameCut` comes off the same string, replacing a comparison of two `.onGeometryChange` widths that landed in different render passes — which is why the warning could be seen switched on over a name still drawn in full. **A second defect surfaced while verifying this.** `.foregroundStyle(.clear)` does not clear a `TextField`'s text; the style reaches the placeholder and the insertion point, not the glyphs UIKit draws. The truncated copy has been drawn *over* a field still showing the full name since #456, invisible for exactly as long as the two strings were identical. The moment the copy became the row's shorter answer it read as an ellipsis stamped across "ww". It is `.opacity` now. The initial `sheetWidth` was `WidgetMetrics.largeWidth` — the width of the panel, where this measures the window the panel is laid out in — making the first pass a row at 88% scale. It is now the narrowest window that draws the grid at full scale, written as the sum it is. Verified on a simulator, which is the only witness that counts here: typed into the running app, the editor and the saved row both read "Crossbow…", and both read "Meditation…" for a longer name. The obvious unit test — compare the pixels of SwiftUI's truncation against the model's prediction — was written and removed: `ImageRenderer` drew "Crossboww…", a string 74.11pt wide, into a 71.75pt column, and this repository already knows not to believe it about layout (#386). A test that fails when the app is right is worse than no test. L1 790/790
`.foregroundStyle(.clear)` not hiding a TextField's text, and the reason no width formula can make one string truncate alike at two point sizes. Both cost this issue real time, and both are invisible to the obvious test: the first only shows when the two strings differ, the second only at a boundary.
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.
Closes #615.
Typing "Crossbowww" showed all ten letters in the editor, under a warning
saying the name would be cut, and saved to a row reading "Crossbow…".
No width formula can fix this
The field drew the name at 17pt in a box
nameMaxWidth × 17/12wide andtruncated it there, on the theory that enlarging both sides of the ratio
keeps the ellipsis on the same character (#482). It does not. A line is
size × Σ(advances) + (count − 1) × tracking(size), and SF's tracking tableis per-size, so 17pt type is proportionally narrower than the ratio
predicts and the field is systematically the more generous of the two.
Measured over 1,296 names, against the row's own cut:
"Crossbowww" is 74.63pt against a 71.75pt column and 101.40pt against a
101.65pt field — cut on one surface, fitting on the other, by a quarter of a
point. Every remaining candidate is still a second truncation asked to agree
with the first by arithmetic, so the second truncation goes:
NameTruncationresolves the row's visible text once, at the row's font, size and column, and
the field draws that string.
isNameCutcomes off the same string, replacing a comparison of two.onGeometryChangewidths landing in different render passes — which is whythe warning could be seen switched on over a name still drawn in full.
A second defect, found while verifying
.foregroundStyle(.clear)does not clear aTextField's text — thestyle reaches the placeholder and the insertion point, not the glyphs UIKit
draws. The truncated copy has been drawn over a field still showing the
full name since #456, invisible for exactly as long as the two strings were
identical. The moment the copy became the row's shorter answer it read as an
ellipsis stamped across "ww". It is
.opacitynow.sheetWidth's initial value wasWidgetMetrics.largeWidth— the width ofthe panel, where this measures the window the panel is laid out in —
making the first pass a row at 88% scale. It is now the narrowest window that
draws the grid at full scale, written as the sum it is.
Testing
L1 790/790Verified in the running app, which is the only witness that counts here: the
editor and the saved row both read "Crossbow…", and both read "Meditation…"
for a longer name.
The obvious unit test was written and removed. Comparing the pixels of
SwiftUI's own truncation against the model's prediction fails: asked for
"Crossbowww" in a 71.75pt column,
ImageRendererdraws "Crossboww…" — astring measuring 74.11pt, wider than the column it was given — while the
running app draws "Crossbow…". This repository already knows not to believe
ImageRendererabout layout (#386), and a test that fails when the app isright is worse than no test. What stays is arithmetic, including the
invariant the overlay depends on: the row's visible text always fits the
field that quotes it, checked across 288 names.
🤖 Generated with Claude Code