Skip to content

feat: measure a line budget with clampMarkdownToLines - #28

Open
mike-doctorina wants to merge 1 commit into
masterfrom
feat/line-clamp
Open

mike-doctorina wants to merge 1 commit into
masterfrom
feat/line-clamp

Conversation

@mike-doctorina

@mike-doctorina mike-doctorina commented Sep 14, 2026 •

Copy link
Copy Markdown
Collaborator

Split out of #27 — it has nothing to do with the selection chrome that PR is about, and nothing inside the package calls it.

What

The renderer has no maxLines and is not gaining one. A host that wants a collapsed preview needs to know where the Nth visual text line ends, so it can size a clipped box without cutting a line in half.

final clamp = clampMarkdownToLines(
  markdown: model,
  theme: theme,
  maxWidth: constraints.maxWidth,
  maxLines: 6,
);
// clamp.height        — full content height
// clamp.clampedHeight — ends on a line boundary
// clamp.overflows     — whether the budget left content out

Counting comes from the new MarkdownPainter.textLineBottoms() (@meta.internal):

  • runs that share a bottom edge — a table row's cells, a bullet and its first line — count as one line;
  • blocks with no text of their own (MD$Spacer, MD$Divider) add height without spending the budget, so a clamp never ends on trailing blank space.

Why it is its own PR

grep -rn "clampMarkdownToLines\|textLineBottoms\|MarkdownLineClamp" lib/ example/lib finds only the definitions. Zero callers in the package, zero in the example — the only thing that ever exercised the line-counting heuristic was its own unit tests, so it deserves its own read rather than riding along in an 8k-line selection PR.

Cost

It is a full layout per call on a throwaway painter. Documented as such; callers must cache and must not call it from build on every frame.

Tests

12 cases in test/line_clamp/line_clamp_test.dart, wired into test/unit_test.dart: budget not exceeded, cut lands on the last allowed line, soft-wrapped paragraph, list items, blank lines and dividers adding height without spending the budget, zero and negative budgets, empty document, table rows, a quote with a nested fence, and a zero measuring width.

flutter test test/unit_test.dart → 990 passed. dart analyze --fatal-infos --fatal-warnings lib/ test/ → clean.


Credit: the original implementation is @itsezlife's, from #27. It is split out here unchanged in substance; the commit is under my name only because the branch was assembled from that PR — the work is theirs.

The renderer has no maxLines and is not gaining one. A host that wants a
collapsed preview needs to know where the Nth visual text line ends so it can
size a clipped box without cutting a line in half.

clampMarkdownToLines lays the document out on a throwaway painter and reports
(height, clampedHeight). Counting comes from MarkdownPainter.textLineBottoms():
runs that share a bottom edge — a table row's cells, a bullet and its first
line — count as one line, and blocks with no text of their own (spacer,
divider) add height without spending the budget, so a clamp never ends on
trailing blank space.

Split out of #27: nothing inside the package calls it and it has
no bearing on the selection work that PR is about.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants