Gemini/GeminiFormat/TableOfContents.swift

72 lines
2.0 KiB
Swift

//
// TableOfContents.swift
// GeminiFormat
//
// Created by Shadowfacts on 12/19/20.
//
import Foundation
public struct TableOfContents {
public let entries: [Entry]
public init(document: Document) {
self.entries = TableOfContents.entries(lines: document.lines)
}
private static func entries(lines: [Document.Line]) -> [Entry] {
var topLevelEntries = [Entry]()
var currentEntries = [Entry]()
var index = 0
while index < lines.count {
defer { index += 1 }
let line = lines[index]
guard case let .heading(_, level: level) = line else {
continue
}
let newEntry = Entry(line: line, lineIndex: index)
while !currentEntries.isEmpty && level <= currentEntries.last!.level {
currentEntries.removeLast()
}
if let last = currentEntries.last {
last.children.append(newEntry)
currentEntries.append(newEntry)
} else {
topLevelEntries.append(newEntry)
currentEntries.append(newEntry)
}
}
return topLevelEntries
}
}
public extension TableOfContents {
class Entry: Equatable {
public let line: Document.Line
let level: Document.HeadingLevel
public let lineIndex: Int
public fileprivate(set) var children: [Entry]
init(line: Document.Line, lineIndex: Int) {
guard case let .heading(_, level: level) = line else { fatalError() }
self.line = line
self.level = level
self.lineIndex = lineIndex
self.children = []
}
public static func ==(lhs: Entry, rhs: Entry) -> Bool {
return lhs.line == rhs.line && lhs.lineIndex == rhs.lineIndex && lhs.children == rhs.children
}
}
}