krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Sources/OrgCore/Semantic/TableModel.swift

322a87d47526d505d903e05d14e65a5464e1468f
orgstar/Sources/OrgCore/Semantic/TableModel.swift history · blame · raw

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}