Gemini/GeminiFormat/Document.swift

92 lines
2.4 KiB
Swift

//
// Document.swift
// GeminiFormat
//
// Created by Shadowfacts on 7/12/20.
//
import Foundation
public struct Document {
public let url: URL
public var lines: [Line]
public init(url: URL, lines: [Line] = []) {
self.url = url
self.lines = lines
}
/// Renders this Document to Gemini formatted text. This is not guaranteed to be the original input text.
public func toGeminiText() -> String {
// todo: should this be \r\n
return lines.map { $0.geminiText() }.joined(separator: "\n")
}
public var title: String? {
for case let .heading(text, level: _) in lines {
return text
}
return nil
}
}
public extension Document {
enum Line: Equatable {
case text(String)
case link(URL, text: String?)
case preformattedToggle(alt: String?)
case preformattedText(String)
case heading(String, level: HeadingLevel)
case unorderedListItem(String)
case quote(String)
func geminiText() -> String {
switch self {
case let .text(text):
return text
case let .link(url, text: text):
if let text = text {
return "=> \(url.absoluteString) \(text)"
} else {
return "=> \(url.absoluteString)"
}
case let .preformattedToggle(alt: alt):
if let alt = alt {
return "```\(alt)"
} else {
return "```"
}
case let .preformattedText(text):
return text
case let .heading(text, level: level):
return "\(level.geminiText) \(text)"
case let .unorderedListItem(text):
return "* \(text)"
case let .quote(text):
return "> \(text)"
}
}
}
}
public extension Document {
enum HeadingLevel: Int, Comparable {
case h1 = 1, h2 = 2, h3 = 3
var geminiText: String {
switch self {
case .h1:
return "#"
case .h2:
return "##"
case .h3:
return "###"
}
}
public static func < (lhs: Document.HeadingLevel, rhs: Document.HeadingLevel) -> Bool {
return lhs.rawValue < rhs.rawValue
}
}
}