86 lines
2.4 KiB
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
|
|
}
|
|
}
|
|
}
|