Skip to content

fix(chat): size a list's indent to its widest marker in the Chat font - #2096

Merged
devswha merged 1 commit into
mainfrom
fix/chat-list-number-indent
Oct 28, 2026
Merged

devswha merged 1 commit into
mainfrom
fix/chat-list-number-indent

Conversation

@devswha

@devswha devswha commented Oct 28, 2026

Copy link
Copy Markdown
Owner

Fixes #1993, reported by @Hyd3-14.

A list's markers sit outside its items, inside .markdown-list's fixed padding-left: 20px, and are drawn in the Chat font. In a monospace Chat font each digit and the . after it take a whole cell, so 1. is about 27px at the chat size and its first digit was cut off at the transcript's left edge. Lists that reach 10. overflowed even in the default Pretendard face (10. is 26px there).

Summary

  • src/components/ChatView.css: the indent is the widest marker measured in cells (ch) of the list's own font, and never less than the 20px it was:
    • bullet lists: max(var(--space-5), 2ch). In the default face at the default size this is still 20px. It grows only where • needs more, for example monospace at 24px, where the bullet was clipped too.
    • numbered lists: max(var(--space-5), calc((var(--markdown-list-digits) + 2) * 1ch)). Monospace N. is exactly digits + 2 cells, whatever the face's cell width (HackGen35 is a 3:5 face, so its cell is 0.6em), and a proportional face's . is narrower than two cells.
    • --markdown-list-digits resets to 1 on every list, so a nested list does not inherit its parent's value.
  • src/components/Markdown.tsx: an ordered list with a multi-digit widest number sets --markdown-list-digits inline. Past a 32-bit integer the browser ignores start and counts from 1, so such a start sets no wider indent.
  • src/lib/markdown.test.ts: covers the digit count, including nested lists and the 32-bit limit.
  • scripts/chat-list-markers-demo-regression.ts (new, in scripts/ci-browser.sh): runs the unmodified app over the demo's fixture transport, at 390px and 1440px, in the default face, in monospace, and in monospace at the largest Chat size (24px). It measures every marker of a reply's lists (1-3, 8-12, 99-100, bullets and a nested bullet) as the browser draws it, in the marker's own computed font, and checks that it fits its list's indent. In the default face it also checks that a bullet list keeps its 20px.
  • changelog.d/chat-list-number-indent.md.

Visible change

In the default face, a numbered list whose numbers are all one digit now indents 3ch, about 27px at 15px, instead of 20px. Bullet lists keep 20px. CSS cannot give these the old 20px and still fit monospace: any indent built from ch and em that fits monospace 1. is wider than 20px in Pretendard, whose ch (0.6em) is wider than a monospace one (0.5em). Telling the face apart would take a runtime measurement, so I did not try.

Design precedent

This follows T3 Code. Its chat ol renderer widens an inherited --list-gutter with an inline style for lists whose widest marker has more than one character, so list-style-position: outside does not paint the marker past the padding box. Every ol and ul resets the variable, so nested lists keep their own value (index.css#L1846-L1868). The difference is that T3's gutter is in rem, while ours is in ch: our Chat font is the user's choice, and the marker is drawn in it.

Verification

  • bun scripts/chat-list-markers-demo-regression.ts fails on main at its first case (default face, 390px: 10. to 12. and 99. are 26px and 100. is 35.2px, all in a 20px indent). With this fix it prints PASS for all six cases (390/1440 × default/monospace/monospace 24px). The monospace markers fill their indents exactly (100. 45.2px in 45.2px).
  • Screenshots of the same transcript on main and with the fix: on main, monospace shows 1. as . and the default face clips the first digit of 10. and up; with the fix every number is whole.
  • bun test src/lib/markdown.test.ts: the new digit-count case fails when the 32-bit limit is removed (it counts 21 digits) and passes with it.
  • bun run check fast green (7720 pass) on the tree before the rebase. Main's commits since then touch none of these files, and typecheck plus the touched test files pass again on the rebased head.
  • One earlier check fast run failed in two files this PR does not touch, scripts/check.test.ts (/tmp/...: No space left on device) and scripts/ci-browser.test.ts (a 5 s timeout at load 93 on 128 cores). /tmp then had 36G free, and the rerun was green.

Reviews

  • omo-native-code-reviewer: APPROVE. No CRITICAL, HIGH or MEDIUM; four LOWs, covered below.
  • Codex Sol 6.1 Fast xhigh: BLOCK on one MEDIUM. A start past a 32-bit integer (100000000000000000000.) gave a 21-digit indent (about 330px) for a list the browser numbers from 1. Fixed in Markdown.tsx, with a unit test. Chrome was probed for this: start="2147483648" reads back as start 1.
  • LOWs left as they are:
    • Task boxes: at 24px monospace a task box can overhang its list's indent by about 3px. This was already so, the fix narrows it, and it is a follow-up issue.
    • The regression checks that each marker's drawn width fits the indent, not that nothing crops it (a clip-path added to the list would pass).
    • The regression's marker table knows only the bullet and decimal styles, which are the ones the chat draws.

Fixes #1993, reported by @Hyd3-14. A list's markers sit outside its
items, in the list's indent, and are drawn in the Chat font; a fixed
20px cut the first digit of "1." off in a monospace Chat font, and of
"10." and up in the default face.

The indent is now the widest marker in cells of the list's own font,
never less than 20px: max(20px, 2ch) for bullets and
max(20px, (digits + 2)ch) for numbers, the digits of the widest number
passed in from Markdown.tsx (a start past a 32-bit integer, which the
browser ignores, sets no wider indent). The new demo regression
measures every marker in its own font against its list's indent at a
phone's and a desktop's width.
@coderabbitai

coderabbitai Bot commented Oct 28, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 11 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 65ffea6 and 44e550d.

Files selected for processing: 6
  • changelog.d/chat-list-number-indent.md
  • scripts/chat-list-markers-demo-regression.ts
  • scripts/ci-browser.sh
  • src/components/ChatView.css
  • src/components/Markdown.tsx
  • src/lib/markdown.test.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devswha

devswha commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

CI notes for the merge pass:

  • Integration tests failed on attempt 1 (run 40606183023) in one test, server/opencode.contract.test.ts:1037 "never waits on the event stream before the first key, in all three delivery paths". It measured prompt/slow at 1063 ms against its 1000 ms bound. This PR touches no server code. One rerun of the failed job passed, and every check is now green on 44e550d. None of the last 40 CI runs had failed this test, so it is a first sighting. I filed nothing yet; it is worth watching.
  • scripts/chat-list-markers-demo-regression.ts passed in CI (Browser regression, other scripts).
  • CodeRabbit was rate-limited ("Review limit reached") and did not review this head. The reviews that ran are omo-native-code-reviewer (APPROVE) and Codex Sol 6.1 Fast xhigh (one MEDIUM, fixed); see the PR body.

@devswha

devswha commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

Merging 44e550d: omo-native-code-reviewer and Codex both pass this head (LOW notes only), and the required checks are green. CodeRabbit did not review this head. The LOW notes go to a follow-up issue.

@devswha
devswha merged commit 1953194 into main Oct 28, 2026
18 of 20 checks passed
@devswha
devswha deleted the fix/chat-list-number-indent branch October 28, 2026 00:33
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.

Chat: numbered list markers are cut off on the left with a wide Chat font

1 participant