1
1
//
2
- // ImageClassPicker .swift
2
+ // ImageRuntimeObjectsView .swift
3
3
// HeaderViewer
4
4
//
5
5
// Created by Leptos on 2/20/24.
@@ -15,7 +15,7 @@ private enum ImageLoadState {
15
15
case loadError( Error )
16
16
}
17
17
18
- private class ImageClassPickerModel : ObservableObject {
18
+ private class ImageRuntimeObjectsViewModel : ObservableObject {
19
19
let namedNode : NamedNode
20
20
21
21
let imagePath : String
@@ -24,13 +24,21 @@ private class ImageClassPickerModel: ObservableObject {
24
24
let runtimeListings : RuntimeListings = . shared
25
25
26
26
@Published var searchString : String
27
+ @Published var searchScope : RuntimeTypeSearchScope
27
28
28
29
@Published private( set) var classNames : [ String ] // not filtered
30
+ @Published private( set) var protocolNames : [ String ] // not filtered
29
31
@Published private( set) var runtimeObjects : [ RuntimeObjectType ] // filtered based on search
30
32
@Published private( set) var loadState : ImageLoadState
31
33
32
- private static func runtimeObjectsFor( classNames: [ String ] , searchString: String ) -> [ RuntimeObjectType ] {
33
- let ret : [ RuntimeObjectType ] = classNames. map { . class( named: $0) }
34
+ private static func runtimeObjectsFor( classNames: [ String ] , protocolNames: [ String ] , searchString: String , searchScope: RuntimeTypeSearchScope ) -> [ RuntimeObjectType ] {
35
+ var ret : [ RuntimeObjectType ] = [ ]
36
+ if searchScope. includesClasses {
37
+ ret += classNames. map { . class( named: $0) }
38
+ }
39
+ if searchScope. includesProtocols {
40
+ ret += protocolNames. map { . protocol( named: $0) }
41
+ }
34
42
if searchString. isEmpty { return ret }
35
43
return ret. filter { $0. name. localizedCaseInsensitiveContains ( searchString) }
36
44
}
@@ -43,12 +51,20 @@ private class ImageClassPickerModel: ObservableObject {
43
51
self . imageName = namedNode. name
44
52
45
53
let classNames = CDUtilities . classNamesIn ( image: imagePath)
54
+ let protocolNames = runtimeListings. imageToProtocols [ CDUtilities . patchImagePathForDyld ( imagePath) ] ?? [ ]
46
55
self . classNames = classNames
56
+ self . protocolNames = protocolNames
47
57
48
58
let searchString = " "
59
+ let searchScope : RuntimeTypeSearchScope = . all
60
+
49
61
self . searchString = searchString
62
+ self . searchScope = searchScope
50
63
51
- self . runtimeObjects = Self . runtimeObjectsFor ( classNames: classNames, searchString: searchString)
64
+ self . runtimeObjects = Self . runtimeObjectsFor (
65
+ classNames: classNames, protocolNames: protocolNames,
66
+ searchString: searchString, searchScope: searchScope
67
+ )
52
68
53
69
self . loadState = runtimeListings. isImageLoaded ( path: imagePath) ? . loaded : . notLoaded
54
70
@@ -58,13 +74,23 @@ private class ImageClassPickerModel: ObservableObject {
58
74
}
59
75
. assign ( to: & $classNames)
60
76
77
+ runtimeListings. $imageToProtocols
78
+ . map { imageToProtocols in
79
+ imageToProtocols [ CDUtilities . patchImagePathForDyld ( imagePath) ] ?? [ ]
80
+ }
81
+ . assign ( to: & $protocolNames)
82
+
61
83
let debouncedSearch = $searchString
62
84
. debounce ( for: 0.08 , scheduler: RunLoop . main)
63
85
64
- $classNames. combineLatest ( debouncedSearch) { classNames, searchString in
65
- Self . runtimeObjectsFor ( classNames: classNames, searchString: searchString)
66
- }
67
- . assign ( to: & $runtimeObjects)
86
+ $searchScope
87
+ . combineLatest ( debouncedSearch, $classNames, $protocolNames) {
88
+ Self . runtimeObjectsFor (
89
+ classNames: $2, protocolNames: $3,
90
+ searchString: $1, searchScope: $0
91
+ )
92
+ }
93
+ . assign ( to: & $runtimeObjects)
68
94
69
95
runtimeListings. $imageList
70
96
. map { imageList in
@@ -88,12 +114,12 @@ private class ImageClassPickerModel: ObservableObject {
88
114
}
89
115
}
90
116
91
- struct ImageClassPicker : View {
92
- @StateObject private var viewModel : ImageClassPickerModel
117
+ struct ImageRuntimeObjectsView : View {
118
+ @StateObject private var viewModel : ImageRuntimeObjectsViewModel
93
119
@Binding private var selection : RuntimeObjectType ?
94
120
95
121
init ( namedNode: NamedNode , selection: Binding < RuntimeObjectType ? > ) {
96
- _viewModel = StateObject ( wrappedValue: ImageClassPickerModel ( namedNode: namedNode) )
122
+ _viewModel = StateObject ( wrappedValue: ImageRuntimeObjectsViewModel ( namedNode: namedNode) )
97
123
_selection = selection
98
124
}
99
125
@@ -115,19 +141,16 @@ struct ImageClassPicker: View {
115
141
ProgressView ( )
116
142
. scenePadding ( )
117
143
case . loaded:
118
- if viewModel. classNames. isEmpty {
144
+ if viewModel. classNames. isEmpty && viewModel . protocolNames . isEmpty {
119
145
StatusView {
120
- Text ( " \( viewModel. imageName) is loaded however does not appear to contain any classes " )
146
+ Text ( " \( viewModel. imageName) is loaded however does not appear to contain any classes or protocols " )
121
147
. padding ( . top)
122
148
}
123
149
} else {
124
- let runtimeObjects = viewModel. runtimeObjects
125
- ListView ( runtimeObjects, selection: $selection) { runtimeObject in
126
- RuntimeObjectRow ( type: runtimeObject)
127
- }
128
- . id ( runtimeObjects) // don't try to diff the List
129
- . searchable ( text: $viewModel. searchString)
130
- . autocorrectionDisabled ( ) // turn of auto-correct for the search field
150
+ RuntimeObjectsList (
151
+ runtimeObjects: viewModel. runtimeObjects, selectedObject: $selection,
152
+ searchString: $viewModel. searchString, searchScope: $viewModel. searchScope
153
+ )
131
154
}
132
155
case . loadError( let error) :
133
156
StatusView {
0 commit comments