2022-08-16 10:39:05 +02:00
|
|
|
import Foundation
|
|
|
|
import Ink
|
|
|
|
|
|
|
|
struct PageContentGenerator {
|
|
|
|
|
2022-08-16 12:26:45 +02:00
|
|
|
private let files: FileProcessor
|
2022-08-16 10:39:05 +02:00
|
|
|
|
2022-08-16 12:26:45 +02:00
|
|
|
init(files: FileProcessor) {
|
|
|
|
self.files = files
|
2022-08-16 10:39:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func generate(page: Page, language: String, at url: URL) throws -> String {
|
|
|
|
var errorToThrow: Error? = nil
|
|
|
|
|
|
|
|
let content = try wrap(.missingPage(page: url.path, language: language)) {
|
|
|
|
try String(contentsOf: url)
|
|
|
|
}
|
|
|
|
|
|
|
|
var hasCodeContent = false
|
|
|
|
|
|
|
|
let imageModifier = Modifier(target: .images) { html, markdown in
|
|
|
|
let result = processMarkdownImage(markdown: markdown, html: html, page: page)
|
|
|
|
switch result {
|
|
|
|
case .success(let content):
|
|
|
|
return content
|
|
|
|
case .failure(let error):
|
|
|
|
errorToThrow = error
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let codeModifier = Modifier(target: .codeBlocks) { html, markdown in
|
|
|
|
if markdown.starts(with: "```swift") {
|
|
|
|
#warning("Syntax highlight swift code")
|
|
|
|
return html
|
|
|
|
}
|
|
|
|
hasCodeContent = true
|
|
|
|
return html
|
|
|
|
}
|
|
|
|
let parser = MarkdownParser(modifiers: [imageModifier, codeModifier])
|
|
|
|
|
|
|
|
#warning("Check links in markdown for (missing) files to copy")
|
|
|
|
if hasCodeContent {
|
|
|
|
#warning("Automatically add hljs hightlighting if code samples are found")
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = parser.html(from: content)
|
|
|
|
if let error = errorToThrow {
|
|
|
|
throw error
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
private func processMarkdownImage(markdown: Substring, html: String, page: Page) -> Result<String, Error> {
|
|
|
|
let fileAndTitle = markdown
|
|
|
|
.components(separatedBy: "(").last!
|
|
|
|
.components(separatedBy: ")").first!
|
|
|
|
|
|
|
|
let file = fileAndTitle.components(separatedBy: " \"").first! // Remove title
|
|
|
|
let rightSubtitle: String?
|
|
|
|
if fileAndTitle.contains(" \"") {
|
|
|
|
rightSubtitle = fileAndTitle.dropBeforeFirst("\"").dropAfterLast("\"")
|
|
|
|
} else {
|
|
|
|
rightSubtitle = nil
|
|
|
|
}
|
|
|
|
let leftSubtitle = markdown
|
|
|
|
.components(separatedBy: "]").first!
|
|
|
|
.components(separatedBy: "[").last!.nonEmpty
|
|
|
|
|
|
|
|
#warning("Specify page image width in configuration")
|
|
|
|
let pageImageWidth = 748
|
|
|
|
let size: NSSize
|
|
|
|
let imagePath = page.pathRelativeToRootForContainedInputFile(file)
|
|
|
|
do {
|
2022-08-16 12:26:45 +02:00
|
|
|
size = try files.requireImage(
|
2022-08-16 10:39:05 +02:00
|
|
|
source: imagePath,
|
|
|
|
destination: imagePath,
|
|
|
|
width: pageImageWidth,
|
|
|
|
desiredHeight: nil,
|
|
|
|
createDoubleVersion: true)
|
|
|
|
} catch {
|
|
|
|
return .failure(error)
|
|
|
|
}
|
|
|
|
let file2x = file.insert("@2x", beforeLast: ".")
|
|
|
|
#warning("Move HTML code to single location")
|
|
|
|
let result = articelImage(
|
|
|
|
image: file,
|
|
|
|
image2x: file2x,
|
|
|
|
width: size.width,
|
|
|
|
height: size.height,
|
|
|
|
rightSubtitle: rightSubtitle,
|
|
|
|
leftSubtitle: leftSubtitle)
|
|
|
|
return .success(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
private func articelImage(image: String, image2x: String, width: CGFloat, height: CGFloat, rightSubtitle: String?, leftSubtitle: String?) -> String {
|
|
|
|
let subtitleCode = subtitle(left: leftSubtitle, right: rightSubtitle)
|
|
|
|
return fullImageCode(image: image, image2x: image2x, width: width, height: height, subtitle: subtitleCode)
|
|
|
|
}
|
|
|
|
|
|
|
|
private func articleImageWithoutSubtitle(image: String, image2x: String, width: CGFloat, height: CGFloat) -> String {
|
|
|
|
"""
|
|
|
|
<span class="image">
|
|
|
|
<img src="\(image)" srcset="\(image2x) 2x" width="\(Int(width))" height="\(Int(height))" loading="lazy"/>
|
|
|
|
</span>
|
|
|
|
"""
|
|
|
|
}
|
|
|
|
|
|
|
|
private func subtitle(left: String?, right: String?) -> String {
|
|
|
|
guard left != nil || right != nil else {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
let leftCode = left.unwrapped { "<span class=\"left\">\($0)</span>" } ?? ""
|
|
|
|
let rightCode = right.unwrapped { "<span class=\"right\">\($0)</span>" } ?? ""
|
|
|
|
return """
|
|
|
|
<div class="subtitle">
|
|
|
|
\(leftCode)
|
|
|
|
\(rightCode)
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
}
|
|
|
|
|
|
|
|
private func fullImageCode(image: String, image2x: String, width: CGFloat, height: CGFloat, subtitle: String) -> String {
|
|
|
|
"""
|
|
|
|
<span class="image">
|
|
|
|
<img src="\(image)" srcset="\(image2x) 2x" width="\(Int(width))" height="\(Int(height))" loading="lazy"/>
|
|
|
|
\(subtitle)
|
|
|
|
</span>
|
|
|
|
"""
|
|
|
|
}
|
|
|
|
}
|