Gemini/GeminiFormat/GeminiHTMLRenderer.swift

86 lines
2.4 KiB
Swift

//
// GeminiHTMLRenderer.swift
// GeminiRenderer
//
// Created by Shadowfacts on 12/16/20.
//
import Foundation
import HTMLEntities
public class GeminiHTMLRenderer {
public var linkPrefix: ((URL) -> String?)?
public var addHeadingLineIDs = true
public var addLinkClass = true
public init() {
}
public func renderDocumentToHTML(_ doc: Document) -> String {
var str = ""
var inPreformatting = false
var inList = false
for (index, line) in doc.lines.enumerated() {
if inList && !line.isListItem {
str += "</ul>"
inList = false
}
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"
if addLinkClass {
str += " class=\"link\""
}
str += ">\(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)"
if addHeadingLineIDs {
str += " id=\"l\(index)\""
}
str += ">\(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
}
}
extension Document.Line {
var isListItem: Bool {
switch self {
case .unorderedListItem(_):
return true
default:
return false
}
}
}