From 501fdce29e4d2c46c4708ad7f44056878e0db3fa Mon Sep 17 00:00:00 2001 From: Ruben Beltran del Rio Date: Tue, 16 Jun 2026 12:08:21 +0200 Subject: Initial extraction from Norganize --- Sources/NorgKit/Models/NorgBlock.swift | 108 +++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 Sources/NorgKit/Models/NorgBlock.swift (limited to 'Sources/NorgKit/Models/NorgBlock.swift') diff --git a/Sources/NorgKit/Models/NorgBlock.swift b/Sources/NorgKit/Models/NorgBlock.swift new file mode 100644 index 0000000..32e4eeb --- /dev/null +++ b/Sources/NorgKit/Models/NorgBlock.swift @@ -0,0 +1,108 @@ +/// 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 + } + } +} -- cgit