Skip to content

Commit 0713d2c

Browse files
committed
Begin StyledRangeContainer
1 parent 1fa046c commit 0713d2c

File tree

5 files changed

+93
-8
lines changed

5 files changed

+93
-8
lines changed

Sources/CodeEditSourceEditor/Highlighting/HighlighProviding/HighlightProviderState.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class HighlightProviderState {
2424
// MARK: - State
2525

2626
/// A unique identifier for this provider. Used by the delegate to determine the source of results.
27-
private let id: UUID = UUID()
27+
let id: UUID
2828

2929
/// Any indexes that highlights have been requested for, but haven't been applied.
3030
/// Indexes/ranges are added to this when highlights are requested and removed
@@ -58,18 +58,21 @@ class HighlightProviderState {
5858
/// Creates a new highlight provider state object.
5959
/// Sends the `setUp` message to the highlight provider object.
6060
/// - Parameters:
61+
/// - id: The ID of the provider
6162
/// - delegate: The delegate for this provider. Is passed information about ranges to highlight.
6263
/// - highlightProvider: The object to query for highlight information.
6364
/// - textView: The text view to highlight, used by the highlight provider.
6465
/// - visibleRangeProvider: A visible range provider for determining which ranges to query.
6566
/// - language: The language to set up the provider with.
6667
init(
68+
id: UUID = UUID(),
6769
delegate: HighlightProviderStateDelegate,
6870
highlightProvider: HighlightProviding,
6971
textView: TextView,
7072
visibleRangeProvider: VisibleRangeProvider,
7173
language: CodeLanguage
7274
) {
75+
self.id = id
7376
self.delegate = delegate
7477
self.highlightProvider = highlightProvider
7578
self.textView = textView

Sources/CodeEditSourceEditor/Highlighting/Highlighter.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,17 @@ class Highlighter: NSObject {
8787
self.textView = textView
8888
self.attributeProvider = attributeProvider
8989
self.visibleRangeProvider = VisibleRangeProvider(textView: textView)
90-
self.rangeContainer = StyledRangeContainer()
90+
91+
let providerIds = providers.indices.map({ _ in UUID() })
92+
self.rangeContainer = StyledRangeContainer(documentLength: textView.length, providers: providerIds)
9193

9294
super.init()
9395

94-
self.providers = providers.map {
96+
self.providers = providers.enumerated().map { (idx, provider) in
9597
HighlightProviderState(
98+
id: providerIds[idx],
9699
delegate: rangeContainer,
97-
highlightProvider: $0,
100+
highlightProvider: provider,
98101
textView: textView,
99102
visibleRangeProvider: visibleRangeProvider,
100103
language: language

Sources/CodeEditSourceEditor/Highlighting/StyledRangeContainer/StyledRangeContainer.swift

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,49 @@
88
import Foundation
99

1010
class StyledRangeContainer {
11-
private var storage: [UUID: StyledRangeStore] = [:]
11+
typealias Run = StyledRangeStore.Run
12+
var _storage: [UUID: StyledRangeStore] = [:]
13+
14+
init(documentLength: Int, providers: [UUID]) {
15+
for provider in providers {
16+
_storage[provider] = StyledRangeStore(documentLength: documentLength)
17+
}
18+
}
19+
20+
func runsIn(range: NSRange) -> [Run] {
21+
22+
}
23+
24+
func storageUpdated(replacedContentIn range: Range<Int>, withCount newLength: Int) {
25+
_storage.values.forEach {
26+
$0.storageUpdated(replacedCharactersIn: range, withCount: newLength)
27+
}
28+
}
1229
}
1330

1431
extension StyledRangeContainer: HighlightProviderStateDelegate {
1532
func applyHighlightResult(provider: UUID, highlights: [HighlightRange], rangeToHighlight: NSRange) {
16-
guard let storage = storage[provider] else {
33+
assert(rangeToHighlight != .notFound, "NSNotFound is an invalid highlight range")
34+
guard let storage = _storage[provider] else {
1735
assertionFailure("No storage found for the given provider: \(provider)")
1836
return
1937
}
20-
38+
var runs: [Run] = []
39+
var lastIndex = rangeToHighlight.lowerBound
40+
41+
for highlight in highlights {
42+
if highlight.range.lowerBound != lastIndex {
43+
runs.append(.empty(length: highlight.range.lowerBound - lastIndex))
44+
}
45+
// TODO: Modifiers
46+
runs.append(Run(length: highlight.range.length, capture: highlight.capture, modifiers: []))
47+
lastIndex = highlight.range.max
48+
}
49+
50+
if lastIndex != rangeToHighlight.upperBound {
51+
runs.append(.empty(length: rangeToHighlight.upperBound - lastIndex))
52+
}
53+
54+
storage.set(runs: runs, for: rangeToHighlight.intRange)
2155
}
2256
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@ final class StyledRangeStore {
2525
}
2626

2727
/// Consumer-facing value type for the stored values in this container.
28-
struct Run {
28+
struct Run: Equatable, Hashable, Sendable {
2929
let length: Int
3030
let capture: CaptureName?
3131
let modifiers: Set<CaptureModifiers>
32+
33+
static func empty(length: Int) -> Self {
34+
Run(length: length, capture: nil, modifiers: [])
35+
}
3236
}
3337

3438
// MARK: - Core
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import XCTest
2+
@testable import CodeEditSourceEditor
3+
4+
final class StyledRangeContainerTests: XCTestCase {
5+
typealias Run = StyledRangeContainer.Run
6+
7+
func test_init() {
8+
let providers = [UUID(), UUID()]
9+
let store = StyledRangeContainer(documentLength: 100, providers: providers)
10+
11+
// Have to do string conversion due to missing Comparable conformance pre-macOS 14
12+
XCTAssertEqual(store._storage.keys.map(\.uuidString).sorted(), providers.map(\.uuidString).sorted())
13+
XCTAssert(store._storage.values.allSatisfy({ $0.length == 100 }), "One or more providers have incorrect length")
14+
}
15+
16+
func test_setHighlights() {
17+
let providers = [UUID(), UUID()]
18+
let store = StyledRangeContainer(documentLength: 100, providers: providers)
19+
20+
store.applyHighlightResult(
21+
provider: providers[0],
22+
highlights: [HighlightRange(range: NSRange(location: 40, length: 10), capture: .comment)],
23+
rangeToHighlight: NSRange(location: 0, length: 100)
24+
)
25+
26+
XCTAssertNotNil(store._storage[providers[0]])
27+
XCTAssertEqual(store._storage[providers[0]]!.count, 3)
28+
XCTAssertEqual(store._storage[providers[0]]!.runs(in: 0..<100)[0].capture, nil)
29+
XCTAssertEqual(store._storage[providers[0]]!.runs(in: 0..<100)[1].capture, .comment)
30+
XCTAssertEqual(store._storage[providers[0]]!.runs(in: 0..<100)[2].capture, nil)
31+
32+
XCTAssertEqual(
33+
store.runsIn(range: NSRange(location: 0, length: 100)),
34+
[
35+
Run(length: 40, capture: nil, modifiers: []),
36+
Run(length: 10, capture: .comment, modifiers: []),
37+
Run(length: 50, capture: nil, modifiers: [])
38+
]
39+
)
40+
}
41+
}

0 commit comments

Comments
 (0)