Gemini/GeminiRenderer/GeminiHTMLRenderer.swift

76 lines
2.1 KiB
Swift

//
// GeminiHTMLRenderer.swift
// GeminiRenderer
//
// Created by Shadowfacts on 12/16/20.
//
import Foundation
import GeminiFormat
import HTMLEntities
public class GeminiHTMLRenderer {
public var linkPrefix: ((URL) -> String?)?
public init() {
}
public func renderDocumentToHTML(_ doc: Document) -> String {
var str = ""
var inPreformatting = false
var inList = false
for line in doc.lines {
if inList && !line.isListItem {
str += "</ul>"
}
switch line {
case let .text(text):
str += "<p>\(text.htmlEscape())</p>"
case let .link(url, text: maybeText):
let text = maybeText ?? url.absoluteString
let linkPrefix = self.linkPrefix?(url) ?? ""
str += "<p class=\"link\">\(linkPrefix)<a href=\"\(url.absoluteString)\">\(text.htmlEscape())</a></p>"
case .preformattedToggle(alt: _):
inPreformatting = !inPreformatting
if inPreformatting {
str += "<pre>"
} else {
str += "</pre>"
}
case let .preformattedText(text):
str += text.htmlEscape()
str += "\n"
case let .heading(text, level: level):
let tag = "h\(level.rawValue)"
str += "<\(tag)>\(text.htmlEscape())</\(tag)>"
case let .unorderedListItem(text):
if !inList {
inList = true
str += "<ul>"
}
str += "<li>\(text.htmlEscape())</li>"
case let .quote(text):
str += "<blockquote>\(text.htmlEscape())</blockquote>"
}
}
return str
}
}
fileprivate extension Document.Line {
var isListItem: Bool {
switch self {
case .unorderedListItem(_):
return true
default:
return false
}
}
}