Skip to content

feat(apple): give HtmlConfig's optional settings their real Swift types - #807

Merged
andiwand merged 1 commit into
mainfrom
apple/html-config-optionals
Sep 2, 2026
Merged

feat(apple): give HtmlConfig's optional settings their real Swift types#807
andiwand merged 1 commit into
mainfrom
apple/html-config-optionals

Conversation

@andiwand

@andiwand andiwand commented Sep 2, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Closes #759.

HtmlConfig.spreadsheetLimit is a TableDimensions boxed in an NSValue, and Swift has no @encode, so a caller had to write:

config.spreadsheetLimit = withUnsafeBytes(of: TableDimensions(rows: 100_000, columns: 500)) {
    NSValue(bytes: $0.baseAddress!, objCType: "{ODRTableDimensions=II}")
}

That literal is a second source of truth for the struct's layout, sitting in a consumer — opendocument-app/OpenDocument.ios#185 carries it today — and a field added to ODRTableDimensions breaks it silently, because getValue:size: checks the size and not the encoding.

Now:

config.spreadsheetLimit = TableDimensions(rows: 100_000, columns: 500)
config.initialZoom = 1.5

How

The six boxed properties are marked NS_REFINED_FOR_SWIFT, so Swift sees them as __spreadsheetLimit etc., and apple/swift/Html+Optionals.swift — beside Style+Optionals.swift, which solves the read half — carries them under their own names as real optionals:

property was is
spreadsheetLimit NSValue? TableDimensions?
spreadsheetCellLimit NSNumber? UInt64?
spreadsheetViewportMode NSNumber? HtmlViewportMode?
viewportWidth NSNumber? UInt32?
initialZoom NSNumber? Double?
pageRangeEnd NSNumber? UInt32?

@encode stays in the ObjC layer, as an NSValue (ODRTableDimensions) category beside the struct it encodes. ObjC callers see the boxed properties unchanged.

Deviation from the issue's sketch

The issue proposed new names alongside the boxed ones (sheetLimit, zoom), the way Style+Optionals.swift renames fontColorcolor. Refinement is better here: it keeps the names the API already has (no width/pageEnd coinages for properties whose names were already right), and it removes the boxed spelling from Swift rather than leaving both — so the encoding literal cannot be written again. It is the Apple-blessed mechanism for exactly this. apple/AGENTS.md records the rule.

This is a Swift-source-breaking change for anyone assigning the boxes, which today is the one workaround this PR exists to delete. CHANGELOG.md says so.

Verification

macOS slices built and ODR_XCFRAMEWORK=OdrCoreObjC.xcframework swift test: 23 tests, 0 failures, including two new ones — nothing under apple/tests set any of these before, so the write path had no coverage at all.

The end-to-end one renders a 3×2 csv (a csv renders as a spreadsheet, so it needs no fixture) with spreadsheetLimit = (rows: 2, columns: 1) and asserts the third row and second column are gone. Checked non-vacuous: with the limit at 99×99 both assertions fail as expected.

@andiwand
andiwand force-pushed the apple/html-config-optionals branch from d5b53ad to f9bb910 Compare September 2, 2026 18:44
…ypes

`spreadsheetLimit` is an `NSValue`-boxed `ODRTableDimensions`, and Swift has no
`@encode`: a caller had to spell `"{ODRTableDimensions=II}"` out to build the
box at all, which is what OpenDocument.ios#185 carries — a second source of
truth for the struct's layout that a new field would break silently, since
`getValue:size:` checks the size and not the encoding.

The six boxed properties are now `NS_REFINED_FOR_SWIFT`, and
`apple/swift/Html+Optionals.swift` carries them under their own names as real
optionals: `TableDimensions?`, `UInt64?`, `HtmlViewportMode?`, `UInt32?`,
`Double?`, `UInt32?`. `@encode` stays in the ObjC layer, as an
`NSValue (ODRTableDimensions)` category beside the struct. ObjC callers see the
boxed properties unchanged.

Nothing under `apple/tests` set any of them, so the write path had no coverage;
two tests now round-trip all six and prove the sheet limit reaches the html.

Closes #759.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018cMYRXLJdiCkH65Jm2W9B5
@andiwand
andiwand force-pushed the apple/html-config-optionals branch from f9bb910 to a57b7d3 Compare September 2, 2026 18:48
@andiwand
andiwand merged commit fd707e7 into main Sep 2, 2026
29 checks passed
@andiwand
andiwand deleted the apple/html-config-optionals branch September 2, 2026 18:50
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.

apple: a boxed HtmlConfig property cannot be set from Swift without a hand-written type encoding

1 participant