72 lines
2.0 KiB
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
|
||
|
}
|
||
|
}
|
||
|
}
|