@@ -18,7 +18,34 @@ protocol StyledRangeContainerDelegate: AnyObject {
1818/// See ``runsIn(range:)`` for more details on how conflicting highlights are handled.
1919@MainActor
2020class StyledRangeContainer {
21- var _storage : [ ProviderID : StyledRangeStore ] = [ : ]
21+ struct StyleElement : RangeStoreElement , CustomDebugStringConvertible {
22+ var capture : CaptureName ?
23+ var modifiers : CaptureModifierSet
24+
25+ var isEmpty : Bool {
26+ capture == nil && modifiers. isEmpty
27+ }
28+
29+ func combineLowerPriority( _ other: StyleElement ? ) -> StyleElement {
30+ StyleElement (
31+ capture: self . capture ?? other? . capture,
32+ modifiers: modifiers. union ( other? . modifiers ?? [ ] )
33+ )
34+ }
35+
36+ func combineHigherPriority( _ other: StyleElement ? ) -> StyleElement {
37+ StyleElement (
38+ capture: other? . capture ?? self . capture,
39+ modifiers: modifiers. union ( other? . modifiers ?? [ ] )
40+ )
41+ }
42+
43+ var debugDescription : String {
44+ " \( capture? . stringValue ?? " (empty) " ) , \( modifiers) "
45+ }
46+ }
47+
48+ var _storage : [ ProviderID : RangeStore < StyleElement > ] = [ : ]
2249 weak var delegate : StyledRangeContainerDelegate ?
2350
2451 /// Initialize the container with a list of provider identifiers. Each provider is given an id, they should be
@@ -28,13 +55,13 @@ class StyledRangeContainer {
2855 /// - providers: An array of identifiers given to providers.
2956 init ( documentLength: Int , providers: [ ProviderID ] ) {
3057 for provider in providers {
31- _storage [ provider] = StyledRangeStore ( documentLength: documentLength)
58+ _storage [ provider] = RangeStore < StyleElement > ( documentLength: documentLength)
3259 }
3360 }
3461
3562 func addProvider( _ id: ProviderID , documentLength: Int ) {
3663 assert ( !_storage. keys. contains ( id) , " Provider already exists " )
37- _storage [ id] = StyledRangeStore ( documentLength: documentLength)
64+ _storage [ id] = RangeStore < StyleElement > ( documentLength: documentLength)
3865 }
3966
4067 func removeProvider( _ id: ProviderID ) {
@@ -55,10 +82,18 @@ class StyledRangeContainer {
5582 ///
5683 /// - Parameter range: The range to query.
5784 /// - Returns: An array of continuous styled runs.
58- func runsIn( range: NSRange ) -> [ StyledRangeStoreRun ] {
85+ func runsIn( range: NSRange ) -> [ RangeStoreRun < StyleElement > ] {
86+ func combineLowerPriority( _ lhs: inout RangeStoreRun < StyleElement > , _ rhs: RangeStoreRun < StyleElement > ) {
87+ lhs. value = lhs. value? . combineLowerPriority ( rhs. value) ?? rhs. value
88+ }
89+
90+ func combineHigherPriority( _ lhs: inout RangeStoreRun < StyleElement > , _ rhs: RangeStoreRun < StyleElement > ) {
91+ lhs. value = lhs. value? . combineHigherPriority ( rhs. value) ?? rhs. value
92+ }
93+
5994 // Ordered by priority, lower = higher priority.
6095 var allRuns = _storage. sorted ( by: { $0. key < $1. key } ) . map { $0. value. runs ( in: range. intRange) }
61- var runs : [ StyledRangeStoreRun ] = [ ]
96+ var runs : [ RangeStoreRun < StyleElement > ] = [ ]
6297
6398 var minValue = allRuns. compactMap { $0. last } . enumerated ( ) . min ( by: { $0. 1 . length < $1. 1 . length } )
6499
@@ -70,9 +105,9 @@ class StyledRangeContainer {
70105 for idx in ( 0 ..< allRuns. count) . reversed ( ) where idx != minRunIdx {
71106 guard let last = allRuns [ idx] . last else { continue }
72107 if idx < minRunIdx {
73- minRun . combineHigherPriority ( last)
108+ combineHigherPriority ( & minRun , last)
74109 } else {
75- minRun . combineLowerPriority ( last)
110+ combineLowerPriority ( & minRun , last)
76111 }
77112
78113 if last. length == minRun. length {
@@ -93,8 +128,8 @@ class StyledRangeContainer {
93128 }
94129
95130 func storageUpdated( replacedContentIn range: Range < Int > , withCount newLength: Int ) {
96- _storage. values . forEach {
97- $0 . storageUpdated ( replacedCharactersIn: range, withCount: newLength)
131+ for key in _storage. keys {
132+ _storage [ key ] ? . storageUpdated ( replacedCharactersIn: range, withCount: newLength)
98133 }
99134 }
100135}
@@ -109,11 +144,11 @@ extension StyledRangeContainer: HighlightProviderStateDelegate {
109144 /// - rangeToHighlight: The range to apply the highlights to.
110145 func applyHighlightResult( provider: ProviderID , highlights: [ HighlightRange ] , rangeToHighlight: NSRange ) {
111146 assert ( rangeToHighlight != . notFound, " NSNotFound is an invalid highlight range " )
112- guard let storage = _storage [ provider] else {
147+ guard var storage = _storage [ provider] else {
113148 assertionFailure ( " No storage found for the given provider: \( provider) " )
114149 return
115150 }
116- var runs : [ StyledRangeStoreRun ] = [ ]
151+ var runs : [ RangeStoreRun < StyleElement > ] = [ ]
117152 var lastIndex = rangeToHighlight. lowerBound
118153
119154 for highlight in highlights {
@@ -123,10 +158,9 @@ extension StyledRangeContainer: HighlightProviderStateDelegate {
123158 continue // Skip! Overlapping
124159 }
125160 runs. append (
126- StyledRangeStoreRun (
161+ RangeStoreRun < StyleElement > (
127162 length: highlight. range. length,
128- capture: highlight. capture,
129- modifiers: highlight. modifiers
163+ value: StyleElement ( capture: highlight. capture, modifiers: highlight. modifiers)
130164 )
131165 )
132166 lastIndex = highlight. range. max
@@ -137,6 +171,7 @@ extension StyledRangeContainer: HighlightProviderStateDelegate {
137171 }
138172
139173 storage. set ( runs: runs, for: rangeToHighlight. intRange)
174+ _storage [ provider] = storage
140175 delegate? . styleContainerDidUpdate ( in: rangeToHighlight)
141176 }
142177}
0 commit comments