/// A block-level element of a Norg document, including its line position in /// the source. public enum NorgBlock: Equatable, Hashable, Sendable, Codable { case heading(level: Int, status: TaskStatus?, content: [InlineSpan], line: Int) case paragraph(content: [InlineSpan], line: Int) case unorderedListItem(level: Int, status: TaskStatus?, content: [InlineSpan], line: Int) case orderedListItem(level: Int, status: TaskStatus?, content: [InlineSpan], line: Int) case quote(level: Int, status: TaskStatus?, content: [InlineSpan], line: Int) case codeBlock(language: String?, code: String, line: Int) case definition(title: [InlineSpan], status: TaskStatus?, body: [NorgBlock], line: Int) case footnote(title: [InlineSpan], status: TaskStatus?, body: [NorgBlock], line: Int) case tableCell(title: [InlineSpan], status: TaskStatus?, body: [NorgBlock], line: Int) case rangedTag(name: [String], parameters: [String], content: String, line: Int) case horizontalRule(line: Int) case weakDelimiter(line: Int) case strongDelimiter(line: Int) /// The source line on which the block begins. public var line: Int { switch self { case .heading(_, _, _, let line), .paragraph(_, let line), .unorderedListItem(_, _, _, let line), .orderedListItem(_, _, _, let line), .quote(_, _, _, let line), .codeBlock(_, _, let line), .definition(_, _, _, let line), .footnote(_, _, _, let line), .tableCell(_, _, _, let line), .rangedTag(_, _, _, let line), .horizontalRule(let line), .weakDelimiter(let line), .strongDelimiter(let line): return line } } /// The task status attached to the block, if any. public var status: TaskStatus? { switch self { case .heading(_, let status, _, _), .unorderedListItem(_, let status, _, _), .orderedListItem(_, let status, _, _), .quote(_, let status, _, _), .definition(_, let status, _, _), .footnote(_, let status, _, _), .tableCell(_, let status, _, _): return status default: return nil } } /// The block's inline styled content (eg. text of a heading/paragraph, or /// title of a definition/footnote). public var content: [InlineSpan]? { switch self { case .heading(_, _, let content, _), .paragraph(let content, _), .unorderedListItem(_, _, let content, _), .orderedListItem(_, _, let content, _), .quote(_, _, let content, _): return content case .definition(let title, _, _, _), .footnote(let title, _, _, _), .tableCell(let title, _, _, _): return title default: return nil } } /// The nested blocks owned by a range-able block (definition, footnote, or /// table cell). public var body: [NorgBlock]? { switch self { case .definition(_, _, let body, _), .footnote(_, _, let body, _), .tableCell(_, _, let body, _): return body default: return nil } } /// Returns a copy of the block with its task status replaced (pass `nil` to /// clear it). Blocks that cannot carry a status are returned unchanged. public func settingStatus(_ status: TaskStatus?) -> NorgBlock { switch self { case .heading(let level, _, let content, let line): return .heading(level: level, status: status, content: content, line: line) case .unorderedListItem(let level, _, let content, let line): return .unorderedListItem(level: level, status: status, content: content, line: line) case .orderedListItem(let level, _, let content, let line): return .orderedListItem(level: level, status: status, content: content, line: line) case .quote(let level, _, let content, let line): return .quote(level: level, status: status, content: content, line: line) case .definition(let title, _, let body, let line): return .definition(title: title, status: status, body: body, line: line) case .footnote(let title, _, let body, let line): return .footnote(title: title, status: status, body: body, line: line) case .tableCell(let title, _, let body, let line): return .tableCell(title: title, status: status, body: body, line: line) default: return self } } }