Skip to content

Commit

Permalink
Clarify and simplify didChangeContent(in:delta:), add test
Browse files Browse the repository at this point in the history
  • Loading branch information
mattmassicotte committed May 6, 2022
1 parent 126ece2 commit ca1c369
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
23 changes: 22 additions & 1 deletion Sources/Neon/Highlighter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,34 @@ extension Highlighter {
}

extension Highlighter {
/// Calculates any newly-visible text that is invalid
///
/// You should invoke this method when the visible text
/// in your system changes.
public func visibleContentDidChange() {
let set = invalidSet.intersection(visibleSet)

invalidate(.set(set))
}

public func didChangeContent(in range: NSRange, delta: Int, limit: Int) {
/// Update internal state in response to an edit.
///
/// This method must be invoked on every text change. The `range`
/// parameter must refer to the range of text that **was** changed.
/// Consider the example text `"abc"`.
///
/// Inserting a "d" at the end:
///
/// range = NSRange(3..<3)
/// delta = 1
///
/// Deleting the middle "b":
///
/// range = NSRange(1..<2)
/// delta = -1
public func didChangeContent(in range: NSRange, delta: Int) {
let limit = textLength - delta

let mutation = RangeMutation(range: range, delta: delta, limit: limit)

self.validSet = mutation.transform(set: validSet)
Expand Down
4 changes: 4 additions & 0 deletions Sources/Neon/TextContainerSystemInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,14 @@ public struct TextContainerSystemInterface {

extension TextContainerSystemInterface: TextSystemInterface {
public func clearStyle(in range: NSRange) {
assert(range.max <= length, "range is out of bounds, is the text state being updated correctly?")

layoutManager?.setTemporaryAttributes([:], forCharacterRange: range)
}

public func applyStyle(to token: Token) {
assert(token.range.max <= length, "range is out of bounds, is the text state being updated correctly?")

guard let attrs = attributeProvider(token) else { return }

layoutManager?.setTemporaryAttributes(attrs, forCharacterRange: token.range)
Expand Down
40 changes: 40 additions & 0 deletions Tests/NeonTests/HighlighterTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import XCTest
import Neon

class MockInterface: TextSystemInterface {
var length: Int
var visibleRange: NSRange

init(length: Int = 0, visibleRange: NSRange = .zero) {
self.length = length
self.visibleRange = visibleRange
}

func clearStyle(in range: NSRange) {
}

func applyStyle(to token: Token) {
}
}

class HighlighterTests: XCTestCase {
func testEditAndVisibleRangeChange() throws {
let interface = MockInterface()

var requestedRange: NSRange? = nil
let provider: TokenProvider = { range, block in
requestedRange = range
block(.success(.noChange))
}

let highlighter = Highlighter(textInterface: interface, tokenProvider: provider)

interface.length = 10
highlighter.didChangeContent(in: NSRange(0..<0), delta: 10)

interface.visibleRange = NSRange(0..<10)
highlighter.visibleContentDidChange()

XCTAssertEqual(requestedRange, NSRange(0..<10))
}
}

0 comments on commit ca1c369

Please sign in to comment.