Skip to content

Commit 8d3cf5a

Browse files
committed
Docs, Docs, Docs
1 parent 957b859 commit 8d3cf5a

File tree

7 files changed

+104
-52
lines changed

7 files changed

+104
-52
lines changed

Sources/CodeEditSourceEditor/Enums/CaptureModifiers.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ extension CaptureModifiers: CustomDebugStringConvertible {
3737
}
3838
}
3939

40-
public struct CaptureModifierSet: OptionSet, Equatable, Hashable {
40+
/// A set of capture modifiers, efficiently represented by a single integer.
41+
public struct CaptureModifierSet: OptionSet, Equatable, Hashable, Sendable {
4142
public let rawValue: UInt
4243

4344
public init(rawValue: UInt) {
@@ -54,7 +55,8 @@ public struct CaptureModifierSet: OptionSet, Equatable, Hashable {
5455
static let modification = CaptureModifierSet(rawValue: 1 << CaptureModifiers.modification.rawValue)
5556
static let documentation = CaptureModifierSet(rawValue: 1 << CaptureModifiers.documentation.rawValue)
5657
static let defaultLibrary = CaptureModifierSet(rawValue: 1 << CaptureModifiers.defaultLibrary.rawValue)
57-
58+
59+
/// All values in the set.
5860
var values: [CaptureModifiers] {
5961
var rawValue = self.rawValue
6062
var values: [Int8] = []

Sources/CodeEditSourceEditor/Highlighting/HighlighProviding/HighlightProviderState.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ protocol HighlightProviderStateDelegate: AnyObject {
1616
func applyHighlightResult(provider: ProviderID, highlights: [HighlightRange], rangeToHighlight: NSRange)
1717
}
1818

19+
/// Keeps track of the valid and pending indices for a single highlight provider in the editor.
20+
///
21+
/// When ranges are invalidated, edits are made, or new text is made visible, this class is notified and queries its
22+
/// highlight provider for invalidated indices.
23+
///
24+
/// Once it knows which indices were invalidated by the edit, it queries the provider for highlights and passes the
25+
/// results to a ``StyledRangeContainer`` to eventually be applied to the editor.
26+
///
27+
/// This class will also chunk the invalid ranges to avoid performing a massive highlight query.
1928
@MainActor
2029
class HighlightProviderState {
2130
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "", category: "HighlightProviderState")

Sources/CodeEditSourceEditor/Highlighting/Highlighter.swift

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,50 +12,53 @@ import SwiftTreeSitter
1212
import CodeEditLanguages
1313
import OSLog
1414

15-
/*
16-
+---------------------------------+
17-
| Highlighter |
18-
| |
19-
| - highlightProviders[] |
20-
| - styledRangeContainer |
21-
| |
22-
| + refreshHighlightsIn(range:) |
23-
+---------------------------------+
24-
|
25-
|
26-
v
27-
+-------------------------------+ +-----------------------------+
28-
| RangeCaptureContainer | ------> | RangeStore |
29-
| | | |
30-
| - manages combined ranges | | - stores raw ranges & |
31-
| - layers highlight styles | | captures |
32-
| + getAttributesForRange() | +-----------------------------+
33-
+-------------------------------+
34-
^
35-
|
36-
|
37-
+-------------------------------+
38-
| HighlightProviderState[] | (one for each provider)
39-
| |
40-
| - keeps valid/invalid ranges |
41-
| - queries providers (async) |
42-
| + updateStyledRanges() |
43-
+-------------------------------+
44-
^
45-
|
46-
|
47-
+-------------------------------+
48-
| HighlightProviding Object | (tree-sitter, LSP, spellcheck)
49-
+-------------------------------+
50-
*/
51-
52-
/// The `Highlighter` class handles efficiently highlighting the `TextView` it's provided with.
53-
/// It will listen for text and visibility changes, and highlight syntax as needed.
15+
/// This class manages fetching syntax highlights from providers, and applying those styles to the editor.
16+
/// Multiple highlight providers can be used to style the editor.
17+
///
18+
/// This class manages multiple objects that help perform this task:
19+
/// - ``StyledRangeContainer``
20+
/// - ``StyledRangeStore``
21+
/// - ``VisibleRangeProvider``
22+
/// - ``HighlightProviderState``
23+
///
24+
/// A hierarchal overview of the highlighter system.
25+
/// ```
26+
/// +---------------------------------+
27+
/// | Highlighter |
28+
/// | |
29+
/// | - highlightProviders[] |
30+
/// | - styledRangeContainer |
31+
/// | |
32+
/// | + refreshHighlightsIn(range:) |
33+
/// +---------------------------------+
34+
/// |
35+
/// | Queries coalesced styles
36+
/// 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() | +-----------------------------+
43+
/// +-------------------------------+
44+
/// ^
45+
/// | Sends highlighted runs
46+
/// |
47+
/// +-------------------------------+
48+
/// | HighlightProviderState[] | (one for each provider)
49+
/// | |
50+
/// | - keeps valid/invalid ranges |
51+
/// | - queries providers (async) |
52+
/// | + updateStyledRanges() |
53+
/// +-------------------------------+
54+
/// ^
55+
/// | Performs edits and sends highlight deltas, as well as calculates syntax captures for ranges
56+
/// |
57+
/// +-------------------------------+
58+
/// | HighlightProviding Object | (tree-sitter, LSP, spellcheck)
59+
/// +-------------------------------+
60+
/// ```
5461
///
55-
/// One should rarely have to directly modify or call methods on this class. Just keep it alive in
56-
/// memory and it will listen for bounds changes, text changes, etc. However, to completely invalidate all
57-
/// highlights use the ``invalidate()`` method to re-highlight all (visible) text, and the ``setLanguage``
58-
/// method to update the highlighter with a new language if needed.
5962
@MainActor
6063
class Highlighter: NSObject {
6164
static private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "", category: "Highlighter")

Sources/CodeEditSourceEditor/Highlighting/StyledRangeContainer/StyledRangeContainer.swift

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,34 @@ protocol StyledRangeContainerDelegate: AnyObject {
1212
func styleContainerDidUpdate(in range: NSRange)
1313
}
1414

15+
/// Stores styles for any number of style providers. Provides an API for providers to store their highlights, and for
16+
/// the overlapping highlights to be queried for a final highlight pass.
17+
///
18+
/// See ``runsIn(range:)`` for more details on how conflicting highlights are handled.
1519
@MainActor
1620
class StyledRangeContainer {
1721
var _storage: [ProviderID: StyledRangeStore] = [:]
1822
weak var delegate: StyledRangeContainerDelegate?
19-
23+
24+
/// Initialize the container with a list of provider identifiers. Each provider is given an id, they should be
25+
/// passed on here so highlights can be associated with a provider for conflict resolution.
26+
/// - Parameters:
27+
/// - documentLength: The length of the document.
28+
/// - providers: An array of identifiers given to providers.
2029
init(documentLength: Int, providers: [ProviderID]) {
2130
for provider in providers {
2231
_storage[provider] = StyledRangeStore(documentLength: documentLength)
2332
}
2433
}
2534

35+
/// Coalesces all styled runs into a single continuous array of styled runs.
36+
///
37+
/// When there is an overlapping, conflicting style (eg: provider 1 gives `.comment` to the range `0..<2`, and
38+
/// provider 2 gives `.string` to `1..<2`), the provider with a lower identifier will be prioritized. In the example
39+
/// case, the final value would be `0..<1=.comment` and `1..<2=.string`.
40+
///
41+
/// - Parameter range: The range to query.
42+
/// - Returns: An array of continuous styled runs.
2643
func runsIn(range: NSRange) -> [HighlightedRun] {
2744
// Ordered by priority, lower = higher priority.
2845
var allRuns = _storage.sorted(by: { $0.key < $1.key }).map { $0.value.runs(in: range.intRange) }
@@ -68,6 +85,12 @@ class StyledRangeContainer {
6885
}
6986

7087
extension StyledRangeContainer: HighlightProviderStateDelegate {
88+
/// Applies a highlight result from a highlight provider to the storage container.
89+
/// - Parameters:
90+
/// - provider: The provider sending the highlights.
91+
/// - highlights: The highlights provided. These cannot be outside the range to highlight, must be ordered by
92+
/// position, but do not need to be continuous. Ranges not included in these highlights will be saved as empty.
93+
/// - rangeToHighlight: The range to apply the highlights to.
7194
func applyHighlightResult(provider: ProviderID, highlights: [HighlightRange], rangeToHighlight: NSRange) {
7295
assert(rangeToHighlight != .notFound, "NSNotFound is an invalid highlight range")
7396
guard let storage = _storage[provider] else {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@ struct HighlightedRun: Equatable, Hashable {
1919
capture == nil && modifiers.isEmpty
2020
}
2121

22-
mutating func combineLowerPriority(_ other: borrowing HighlightedRun) {
22+
mutating package func combineLowerPriority(_ other: borrowing HighlightedRun) {
2323
if self.capture == nil {
2424
self.capture = other.capture
2525
}
2626
self.modifiers.formUnion(other.modifiers)
2727
}
2828

29-
mutating func combineHigherPriority(_ other: borrowing HighlightedRun) {
29+
mutating package func combineHigherPriority(_ other: borrowing HighlightedRun) {
3030
self.capture = other.capture ?? self.capture
3131
self.modifiers.formUnion(other.modifiers)
3232
}
3333

34-
mutating func subtractLength(_ other: borrowing HighlightedRun) {
34+
mutating package func subtractLength(_ other: borrowing HighlightedRun) {
3535
self.length -= other.length
3636
}
3737
}

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ final class StyledRangeStore {
2626
}
2727

2828
// MARK: - Core
29-
29+
30+
/// Find all runs in a range.
31+
/// - Parameter range: The range to query.
32+
/// - Returns: A continuous array of runs representing the queried range.
3033
func runs(in range: Range<Int>) -> [Run] {
3134
assert(range.lowerBound >= 0, "Negative lowerBound")
3235
assert(range.upperBound <= _guts.count(in: OffsetMetric()), "upperBound outside valid range")
@@ -49,13 +52,22 @@ final class StyledRangeStore {
4952

5053
return runs
5154
}
52-
55+
56+
/// Sets a capture and modifiers for a range.
57+
/// - Parameters:
58+
/// - capture: The capture to set.
59+
/// - modifiers: The modifiers to set.
60+
/// - range: The range to write to.
5361
func set(capture: CaptureName, modifiers: CaptureModifierSet, for range: Range<Int>) {
5462
assert(range.lowerBound >= 0, "Negative lowerBound")
5563
assert(range.upperBound <= _guts.count(in: OffsetMetric()), "upperBound outside valid range")
5664
set(runs: [Run(length: range.length, capture: capture, modifiers: modifiers)], for: range)
5765
}
58-
66+
67+
/// Replaces a range in the document with an array of runs.
68+
/// - Parameters:
69+
/// - runs: The runs to insert.
70+
/// - range: The range to replace.
5971
func set(runs: [Run], for range: Range<Int>) {
6072
_guts.replaceSubrange(
6173
range,
@@ -71,6 +83,7 @@ final class StyledRangeStore {
7183
// MARK: - Storage Sync
7284

7385
extension StyledRangeStore {
86+
/// Handles keeping the internal storage in sync with the document.
7487
func storageUpdated(replacedCharactersIn range: Range<Int>, withCount newLength: Int) {
7588
assert(range.lowerBound >= 0, "Negative lowerBound")
7689
assert(range.upperBound <= _guts.count(in: OffsetMetric()), "upperBound outside valid range")

Sources/CodeEditSourceEditor/Highlighting/VisibleRangeProvider.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ protocol VisibleRangeProviderDelegate: AnyObject {
1313
func visibleSetDidUpdate(_ newIndices: IndexSet)
1414
}
1515

16+
/// Provides information to ``HighlightProviderState``s about what text is visible in the editor. Keeps it's contents
17+
/// in sync with a text view and notifies listeners about changes so highlights can be applied to newly visible indices.
1618
@MainActor
1719
class VisibleRangeProvider {
1820
private weak var textView: TextView?

0 commit comments

Comments
 (0)