Sources/OrgCore/Semantic/TableModel.swift
41 lines · 1544 bytes
1import Foundation
2
3public struct TableModel: Sendable, Equatable {
4 public enum Row: Sendable, Equatable {
5 case rule
6 /// Cell text with surrounding blanks trimmed.
7 case cells([String])
8 }
9
10 public let range: Range<Int>
11 public let heading: Int?
12 public let rows: [Row]
13 /// `#+TBLFM:` values in order.
14 public let formulas: [String]
15 /// Widest cell per column, in display columns.
16 public let columnWidths: [Int]
17
18 public var columnCount: Int { columnWidths.count }
19
20 init(node: SyntaxNode, heading: Int?) {
21 range = node.range
22 self.heading = heading
23 rows = node.children.filter { $0.kind == .tableRow }.map { row in
24 let cells = row.children.filter { $0.kind == .tableCell }
25 if cells.isEmpty, row.text.trimmingCharacters(in: .whitespaces).hasPrefix("|-") { return .rule }
26 return .cells(cells.map { $0.text.trimmingCharacters(in: .whitespaces) })
27 }
28 formulas = node.children.filter { $0.kind == .tableFormula }.map {
29 SettingsScanner.keywordValue($0.text.trimmingCharacters(in: .whitespacesAndNewlines)[...])
30 .trimmingCharacters(in: .whitespaces)
31 }
32 var widths: [Int] = []
33 for case .cells(let cells) in rows {
34 for (column, cell) in cells.enumerated() {
35 if column == widths.count { widths.append(0) }
36 widths[column] = max(widths[column], displayWidth(cell))
37 }
38 }
39 columnWidths = widths
40 }
41}