Skip to content

Commit b1511ee

Browse files
committed
Merge branch 'make-styled-range-store-generic' into code-folding/better-folding-calculation
2 parents cd5b7c8 + 0acd458 commit b1511ee

13 files changed

Lines changed: 246 additions & 202 deletions

Sources/CodeEditSourceEditor/Highlighting/Highlighter.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import OSLog
1717
///
1818
/// This class manages multiple objects that help perform this task:
1919
/// - ``StyledRangeContainer``
20-
/// - ``StyledRangeStore``
20+
/// - ``RangeStore``
2121
/// - ``VisibleRangeProvider``
2222
/// - ``HighlightProviderState``
2323
///
@@ -34,12 +34,12 @@ import OSLog
3434
/// |
3535
/// | Queries coalesced styles
3636
/// v
37-
/// +-------------------------------+ +-----------------------------+
38-
/// | StyledRangeContainer | ------> | StyledRangeStore[] |
39-
/// | | | | Stores styles for one provider
40-
/// | - manages combined ranges | | - stores raw ranges & |
41-
/// | - layers highlight styles | | captures |
42-
/// | + getAttributesForRange() | +-----------------------------+
37+
/// +-------------------------------+ +-------------------------+
38+
/// | StyledRangeContainer | ------> | RangeStore[] |
39+
/// | | | | Stores styles for one provider
40+
/// | - manages combined ranges | | - stores raw ranges & |
41+
/// | - layers highlight styles | | captures |
42+
/// | + getAttributesForRange() | +-------------------------+
4343
/// +-------------------------------+
4444
/// ^
4545
/// | Sends highlighted runs
@@ -276,7 +276,7 @@ extension Highlighter: StyledRangeContainerDelegate {
276276
guard let range = NSRange(location: offset, length: run.length).intersection(range) else {
277277
continue
278278
}
279-
storage?.setAttributes(attributeProvider.attributesFor(run.capture), range: range)
279+
storage?.setAttributes(attributeProvider.attributesFor(run.value?.capture), range: range)
280280
offset += range.length
281281
}
282282

Sources/CodeEditSourceEditor/Highlighting/StyledRangeContainer/StyledRangeContainer.swift

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,34 @@ protocol StyledRangeContainerDelegate: AnyObject {
1818
/// See ``runsIn(range:)`` for more details on how conflicting highlights are handled.
1919
@MainActor
2020
class 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
}

Sources/CodeEditSourceEditor/Highlighting/StyledRangeContainer/StyledRangeStore/StyledRangeStore+OffsetMetric.swift

Lines changed: 0 additions & 22 deletions
This file was deleted.

Sources/CodeEditSourceEditor/Highlighting/StyledRangeContainer/StyledRangeStore/StyledRangeStoreRun.swift

Lines changed: 0 additions & 47 deletions
This file was deleted.

Sources/CodeEditSourceEditor/Highlighting/StyledRangeContainer/StyledRangeStore/StyledRangeStore+Coalesce.swift renamed to Sources/CodeEditSourceEditor/RangeStore/RangeStore+Coalesce.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
//
2-
// StyledRangeStore+Internals.swift
2+
// RangeStore+Internals.swift
33
// CodeEditSourceEditor
44
//
55
// Created by Khan Winter on 10/25/24
66
//
77

88
import _RopeModule
99

10-
extension StyledRangeStore {
10+
extension RangeStore {
1111
/// Coalesce items before and after the given range.
1212
///
1313
/// Compares the next run with the run at the given range. If they're the same, removes the next run and grows the
@@ -16,7 +16,7 @@ extension StyledRangeStore {
1616
/// rather than the queried one.
1717
///
1818
/// - Parameter range: The range of the item to coalesce around.
19-
func coalesceNearby(range: Range<Int>) {
19+
mutating func coalesceNearby(range: Range<Int>) {
2020
var index = findIndex(at: range.lastIndex).index
2121
if index < _guts.endIndex && _guts.index(after: index) != _guts.endIndex {
2222
coalesceRunAfter(index: &index)
@@ -30,11 +30,11 @@ extension StyledRangeStore {
3030
}
3131

3232
/// Check if the run and the run after it are equal, and if so remove the next one and concatenate the two.
33-
private func coalesceRunAfter(index: inout Index) {
33+
private mutating func coalesceRunAfter(index: inout Index) {
3434
let thisRun = _guts[index]
3535
let nextRun = _guts[_guts.index(after: index)]
3636

37-
if thisRun.styleCompare(nextRun) {
37+
if thisRun.compareValue(nextRun) {
3838
_guts.update(at: &index, by: { $0.length += nextRun.length })
3939

4040
var nextIndex = index

Sources/CodeEditSourceEditor/Highlighting/StyledRangeContainer/StyledRangeStore/StyledRangeStore+FindIndex.swift renamed to Sources/CodeEditSourceEditor/RangeStore/RangeStore+FindIndex.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//
2-
// StyledRangeStore+FindIndex.swift
2+
// RangeStore+FindIndex.swift
33
// CodeEditSourceEditor
44
//
55
// Created by Khan Winter on 1/6/25.
66
//
77

8-
extension StyledRangeStore {
8+
extension RangeStore {
99
/// Finds a Rope index, given a string offset.
1010
/// - Parameter offset: The offset to query for.
1111
/// - Returns: The index of the containing element in the rope.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// RangeStore+OffsetMetric.swift
3+
// CodeEditSourceEditor
4+
//
5+
// Created by Khan Winter on 10/25/24
6+
//
7+
8+
import _RopeModule
9+
10+
extension RangeStore {
11+
struct OffsetMetric: RopeMetric {
12+
typealias Element = StoredRun
13+
14+
func size(of summary: RangeStore.StoredRun.Summary) -> Int {
15+
summary.length
16+
}
17+
18+
func index(at offset: Int, in element: RangeStore.StoredRun) -> Int {
19+
return offset
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)