File: RenderContext.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (98 lines) | stat: -rw-r--r-- 4,466 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
 This source file is part of the Swift.org open source project

 Copyright (c) 2021-2024 Apple Inc. and the Swift project authors
 Licensed under Apache License v2.0 with Runtime Library Exception

 See https://swift.org/LICENSE.txt for license information
 See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Foundation
import SymbolKit

/// A context object that pre-renders commonly used pieces of content.
///
/// Use this object for a fast pre-rendered content lookup when you are
/// converting nodes in bulk, i.e. when converting a complete documentation model for example.
public struct RenderContext {
    let documentationContext: DocumentationContext
    let bundle: DocumentationBundle
    let renderer: DocumentationContentRenderer
    
    /// Creates a new render context.
    /// - Warning: Creating a render context pre-renders all content that the context provides.
    /// - Parameters:
    ///   - documentationContext: A documentation context.
    ///   - bundle: A documentation bundle.
    public init(documentationContext: DocumentationContext, bundle: DocumentationBundle) {
        self.documentationContext = documentationContext
        self.bundle = bundle
        self.renderer = DocumentationContentRenderer(documentationContext: documentationContext, bundle: bundle)
        createRenderedContent()
    }
    
    /// The pre-rendered content per node reference.
    private(set) public var store = RenderReferenceStore()
    
    /// Creates a set of commonly used pieces of content using the nodes in the given documentation context.
    /// - Note: On macOS and iOS this function creates the content concurrently.
    private mutating func createRenderedContent() {
        let references = documentationContext.knownIdentifiers
        var topics = [ResolvedTopicReference: RenderReferenceStore.TopicContent]()
        let renderer = self.renderer
        let documentationContext = self.documentationContext
        
        let renderContentFor: (ResolvedTopicReference) -> RenderReferenceStore.TopicContent = { reference in
            var dependencies = RenderReferenceDependencies()
            let renderReference = renderer.renderReference(for: reference, dependencies: &dependencies)
            let canonicalPath = documentationContext.shortestFinitePath(to: reference).flatMap { $0.isEmpty ? nil : $0 }
            let reverseLookup = renderer.taskGroups(for: reference)
            
            return RenderReferenceStore.TopicContent(
                renderReference: renderReference,
                canonicalPath: canonicalPath,
                taskGroups: reverseLookup,
                source: documentationContext.documentLocationMap[reference],
                // Uncurated documentation extensions aren't part of `DocumentationContext.knownIdentifiers`, so none of
                // these references are documentation extensions.
                isDocumentationExtensionContent: false,
                renderReferenceDependencies: dependencies
            )
        }
        
        #if os(macOS) || os(iOS) || os(Android) || os(Windows)
        // Concurrently render content on macOS/iOS, Windows & Android
        let results: [(reference: ResolvedTopicReference, content: RenderReferenceStore.TopicContent)] = references.concurrentPerform { reference, results in
            results.append((reference, renderContentFor(reference)))
        }
        for result in results {
            topics[result.reference] = result.content
        }
        
        #elseif os(Linux)
        // Serially render on Linux
        references.forEach {
            topics[$0] = renderContentFor($0)
        }
        #else
        #error("Unexpected platform.")
        #endif
        
        let assets = documentationContext.assetManagers
            .reduce(into: [AssetReference: DataAsset]()) { (storage, element) in
                let (bundleIdentifier, assetManager) = element
            
                for (name, asset) in assetManager.storage {
                    storage[AssetReference(assetName: name, bundleIdentifier: bundleIdentifier)] = asset
                }
            }
        
        // Add all the external content to the topic store
        for (reference, entity) in documentationContext.externalCache {
            topics[reference] = entity.topicContent()
        }
        
        self.store = RenderReferenceStore(topics: topics, assets: assets)
    }
}