Configurable bullet shapes and task checkbox style - #150
Open
luisKisters wants to merge 4 commits into
Open
Conversation
Cut BulletShape.glyph, BulletStyle.sizeScale and BulletStyle.tiered — no embedder set them — and flatten the bullet draw switch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The gap was a fixed 2pt tuned for the font-derived SF Symbol box. A larger configured box needs a larger gap or the label reads as touching it. Both the draw site and the click hit-test take it from the style, so their rects still cannot drift.
…stroke usesSystemSymbol inferred the rendering path from `self == .default`, so an embedder could not ask for the drawn box at default metrics and any future field would silently re-route embedders between the two paths. Make it an explicit `rendering` mode instead. Also lift the ring's hardcoded stroke width into the style, document the bullet-level attribute key, and compare the whole ListStyle for the redisplay check so a later knob cannot be missed. Tests pin the 0-based indentLevel to 1-based ladder conversion across a real nested list, plus the checkbox size and gap geometry.
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.
Bullet markers and task checkboxes are the only list rendering an embedder cannot influence today:
drawBulletMarkerspaints a hardcoded"•"intheme.bodyTextat every nesting depth, anddrawTaskCheckboxespaints the SF Symbolssquare/checkmark.square.fill.ListStylecarries indent and line-height knobs but nothing for the markers themselves.This adds two configuration groups so a host app can restyle both without forking.
API
BulletStyle.shapeLadderis indexed by 1-based nesting depth; the last entry repeats for deeper levels, and an empty ladder falls back to.filledDot. Shapes other than.filledDotareNSBezierPath, so they stay crisp at any scale.Defaults are unchanged
BulletStyle.defaultis[.filledDot], which keeps the exact existing"•"NSString draw — same font, same centring within the marker advance.TaskCheckboxStyle.defaultis.systemSymbol, which keeps the existing SF Symbol branch untouched. All 253 existing tests pass with no edits to them.renderingis an explicit mode rather than an inferredself == .default, so adding a field later cannot silently re-route existing embedders between the two paths.How depth reaches the renderer
MarkdownASTStyler.styleListItemalready computesMarkdownLists.indentLevel(from:)for its indent. It now also writes that depth (1-based) onto the marker range as abulletListLevelattribute, following the existingblockquoteLevelprecedent.drawBulletMarkersreads it and defaults to depth 1 when absent. Both attributes are written together and cleared together by the existing whole-paragraphsetAttributes, so a stale depth cannot survive an edit.Draw / hit-test parity
TaskCheckboxGeometrystays the single source of truth.size(for:style:)andboxX(contentX:size:gap:)are used by bothMarkdownTextLayoutFragment.drawTaskCheckboxesandNativeTextView+TaskCheckbox.taskCheckboxHit, so a configured size or gap moves the drawn box and the click target together.Tests
Added: default-preservation for both styles, ladder clamping, the 0-based
indentLevelto 1-based ladder conversion across a real nested list, and the checkbox size and gap geometry. 255 tests pass.One thing worth your call:
MarkdownLists.indentLevel(from:)is a whitespace heuristic (tabs plus spaces / 2) that does not consultlists.indentPerLevel, so 4-space-indented CommonMark resolves one level deeper than it looks. That is pre-existing behaviour and this PR does not touch it, but the shape ladder makes it visible for the first time.