diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Neon.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Neon.xcscheme index c2de6a8..bec31d0 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/Neon.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/Neon.xcscheme @@ -87,6 +87,16 @@ ReferencedContainer = "container:"> + + + + RangeTarget { - switch target { - case .all: - return .all - case var .range(range): - for mutation in pendingMutations { - guard let newRange = mutation.transform(range: range) else { - return .empty - } - - range = newRange - } - - return .range(range) - case var .set(set): - for mutation in pendingMutations { - set = mutation.transform(set: set) - } - - return .set(set) - } - } - public func continueFillingIfNeeded() { if hasPendingChanges { return diff --git a/Sources/RangeState/RangeTarget.swift b/Sources/RangeState/RangeTarget.swift index f0a2d14..4409bd2 100644 --- a/Sources/RangeState/RangeTarget.swift +++ b/Sources/RangeState/RangeTarget.swift @@ -1,5 +1,7 @@ import Foundation +import Rearrange + public enum RangeTarget: Hashable, Sendable { case set(IndexSet) case range(NSRange) @@ -7,6 +9,18 @@ public enum RangeTarget: Hashable, Sendable { public static let empty = RangeTarget.set(IndexSet()) + public init(_ set: IndexSet) { + self = .set(set) + } + + public init(_ range: NSRange) { + self = .range(range) + } + + public init(_ ranges: [NSRange]) { + self = .set(IndexSet(ranges: ranges)) + } + public func indexSet(with length: Int) -> IndexSet { let set: IndexSet @@ -21,30 +35,49 @@ public enum RangeTarget: Hashable, Sendable { return set } +} +extension RangeTarget { public func union(_ other: RangeTarget) -> RangeTarget { switch (self, other) { - case let (.set(lhs), .set(rhs)): - return RangeTarget.set(lhs.union(rhs)) + case (.set(var set), .set(let rhs)): + set.formUnion(rhs) + return RangeTarget(set) case (.all, _): return RangeTarget.all case (_, .all): return RangeTarget.all - case let (.set(lhs), .range(rhs)): - let set = lhs.union(IndexSet(integersIn: rhs)) + case (.set(var set), .range(let range)): + set.insert(range: range) - return RangeTarget.set(set) + return RangeTarget(set) case let (.range(lhs), .set(rhs)): let set = rhs.union(IndexSet(integersIn: lhs)) - return RangeTarget.set(set) + return RangeTarget(set) case let (.range(lhs), .range(rhs)): - var set = IndexSet() + return RangeTarget([lhs, rhs]) + } + } + + public func apply(mutations: [RangeMutation]) -> RangeTarget { + switch self { + case .all: + return .all + case var .range(range): + for mutation in mutations { + guard let newRange = range.apply(mutation) else { + return .empty + } + + range = newRange + } - set.insert(range: lhs) - set.insert(range: rhs) + return .range(range) + case var .set(set): + set.applying(mutations) - return RangeTarget.set(set) + return .set(set) } } } diff --git a/Sources/TreeSitterClient/TreeSitterClient.swift b/Sources/TreeSitterClient/TreeSitterClient.swift index 92337c3..4534110 100644 --- a/Sources/TreeSitterClient/TreeSitterClient.swift +++ b/Sources/TreeSitterClient/TreeSitterClient.swift @@ -142,13 +142,12 @@ extension TreeSitterClient { } private func handleInvalidation(_ set: IndexSet, sublayers: Bool) { - let target = rangeProcessor.transformTargetToCurrent(.set(set)) - let transformedSet = target.indexSet(with: configuration.lengthProvider()) + let transformedSet = set.apply(rangeProcessor.pendingMutations) configuration.invalidationHandler(transformedSet) if sublayers { - sublayerValidator.invalidate(target) + sublayerValidator.invalidate(.set(transformedSet)) } } diff --git a/Tests/RangeStateTests/RangeTargetTests.swift b/Tests/RangeStateTests/RangeTargetTests.swift new file mode 100644 index 0000000..3045dbb --- /dev/null +++ b/Tests/RangeStateTests/RangeTargetTests.swift @@ -0,0 +1,19 @@ +import XCTest + +import RangeState + +final class RangeTargetTests: XCTestCase { + func testUnion() { + let range = RangeTarget(NSRange(0..<10)) + let set = RangeTarget(IndexSet(integersIn: 10..<20)) + + XCTAssertEqual(RangeTarget.all.union(.all), .all) + XCTAssertEqual(RangeTarget.all.union(range), .all) + XCTAssertEqual(RangeTarget.all.union(set), .all) + XCTAssertEqual(range.union(.all), .all) + XCTAssertEqual(set.union(.all), .all) + + XCTAssertEqual(range.union(set), .set(IndexSet(integersIn: 0..<20))) + XCTAssertEqual(set.union(range), .set(IndexSet(integersIn: 0..<20))) + } +}