import OrgSwift import SwiftUI /// A document prepared for display: inline runs already styled, footnotes already numbered, /// image URLs already resolved, code already highlighted. /// /// The walk happens once, ahead of `body`, because three things it does must not happen per /// layout pass — footnote numbering is sequential and document-wide, syntax highlighting is /// expensive, and both would otherwise re-run every time SwiftUI recomputes a view. struct OrgLayout { var blocks: [OrgBlock] = [] var footnotes: [OrgFootnote] = [] } struct OrgFootnote: Identifiable { var number: Int var text: AttributedString var id: Int { number } } /// A block ready to render. Mirrors ``OrgElement`` minus the cases that resolve away: /// footnote definitions move to ``OrgLayout/footnotes``, and an export block for another /// backend drops entirely. indirect enum OrgBlock: Identifiable { case heading(text: AttributedString, level: Int) case paragraph(AttributedString) case code(AttributedString) case quote([OrgBlock]) case center([OrgBlock]) case verse([AttributedString]) case special(name: String, blocks: [OrgBlock]) case list(OrgListLayout) case table(OrgTableLayout) case image(source: URL, alt: String, caption: AttributedString?) case badges([OrgBadge]) case captioned(caption: AttributedString?, blocks: [OrgBlock]) case rule /// A LaTeX block, or a paragraph that is one display expression and nothing else. case math(OrgMath) /// Positional identity. Blocks are rebuilt wholesale when the source changes, so their /// index in the layout is stable for as long as the layout is. var id: String { String(describing: self).prefix(64).description } } /// One image in a badge row, with the link it stands for when it has one. struct OrgBadge: Identifiable { var source: URL var alt: String var link: URL? var id: URL { source } } struct OrgListLayout { var kind: OrgListKind var items: [Item] struct Item: Identifiable { var checkbox: OrgCheckbox? var term: AttributedString? /// The item's body in source order — usually one paragraph, but an item may hold a /// nested list, a source block, or a table. var blocks: [OrgBlock] var id = UUID() } } struct OrgTableLayout { /// Cell rows only; org's `|---|` rule rows are structure, carried by ``headerRowCount``. var rows: [Row] var headerRowCount: Int var alignments: [OrgAlignment?] struct Row: Identifiable { var cells: [Cell] var id = UUID() } struct Cell: Identifiable { var text: AttributedString var id = UUID() } var columnCount: Int { rows.map(\.cells.count).max() ?? 0 } func alignment(column: Int) -> OrgAlignment? { column < alignments.count ? alignments[column] : nil } }