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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
//
// PreviewViewController.swift
// QuickLook
//
// Created by Ruben Beltran del Rio on 2025-07-11.
//
import Cocoa
import Quartz
import SwiftUI
class PreviewViewController: NSViewController, QLPreviewingController {
override var nibName: NSNib.Name? {
return NSNib.Name("PreviewViewController")
}
override func loadView() {
super.loadView()
}
func preparePreviewOfFile(at url: URL) async throws {
// Read the .wmap file content
let content = try String(contentsOf: url, encoding: .utf8)
// Parse the content to create a ParsedMap
let lexer = Wmap.Lexer(content)
let parser = Wmap.Parser(lexer: lexer)
let parsedMap = parser.parse()
await MainActor.run {
// Clear any existing subviews and force cleanup
view.subviews.forEach { subview in
if let hostingView = subview as? NSHostingView<AnyView> {
hostingView.rootView = AnyView(EmptyView())
}
subview.removeFromSuperview()
}
// Force memory cleanup
autoreleasepool {
// Create the map preview view with error handling
let mapPreview: AnyView
if parsedMap.entities.isEmpty {
// Fallback view for empty or invalid maps
mapPreview = AnyView(
VStack {
Image(systemName: "map")
.font(.system(size: 48))
.foregroundColor(.gray)
Text("quick_look.empty_map.title")
.font(.Theme.Title.emphasized)
.foregroundColor(.Theme.UI.foreground)
Text("quick_look.empty_map.description")
.font(.Theme.Body.regular)
.foregroundColor(.Theme.UI.foreground)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.foregroundColor(.Theme.UI.background)
)
} else {
// Limit entities for memory efficiency in QuickLook
let limitedEntities = Array(parsedMap.entities.prefix(100)) // Limit to first 100 entities
let limitedMap = Wmap.ParsedMap(
entities: limitedEntities, vertexLabels: parsedMap.vertexLabels)
mapPreview = AnyView(MapPreviewView(parsedMap: limitedMap))
}
let hostingView = NSHostingView(rootView: mapPreview)
hostingView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingView)
NSLayoutConstraint.activate([
hostingView.topAnchor.constraint(equalTo: view.topAnchor),
hostingView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
hostingView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
view.needsLayout = true
view.layoutSubtreeIfNeeded()
} // autoreleasepool
}
}
deinit {
// Cleanup when view controller is deallocated
view.subviews.forEach { subview in
if let hostingView = subview as? NSHostingView<AnyView> {
hostingView.rootView = AnyView(EmptyView())
}
subview.removeFromSuperview()
}
}
}
// A SwiftUI view specifically for QuickLook preview
struct MapPreviewView: View {
let parsedMap: Wmap.ParsedMap
@State private var selectedEvolution: StageType = .general
var body: some View {
GeometryReader { geometry in
let mapSize = Dimensions.Map.size
let padding = Dimensions.Map.padding
let totalWidth = mapSize.width + 2 * padding
let totalHeight = mapSize.height + 2 * padding
// Calculate scale to fit the available space
let scaleX = geometry.size.width / totalWidth
let scaleY = geometry.size.height / totalHeight
let scale = min(scaleX, scaleY, 1.0) // Don't scale up, only down
ScrollView([.horizontal, .vertical]) {
MapRenderView(
entities: parsedMap.entities,
evolution: $selectedEvolution
)
.drawingGroup(opaque: false)
.scaleEffect(scale)
.frame(
width: totalWidth * scale,
height: totalHeight * scale
)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.white)
}
}
}
|