Skip to content

Commit c2d30f4

Browse files
authored
AttributeContainer Filtering (#1182)
1 parent 91bdb3b commit c2d30f4

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

Sources/FoundationEssentials/AttributedString/AttributeContainer.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,31 @@ extension AttributeContainer {
104104
storage.hasConstrainedAttributes
105105
}
106106
}
107+
108+
@available(FoundationPreview 6.2, *)
109+
extension AttributeContainer {
110+
/// Returns an attribute container storing only the attributes in `self` with the `inheritedByAddedText` property set to `true`
111+
public func filter(inheritedByAddedText: Bool) -> AttributeContainer {
112+
var storage = self.storage
113+
for (key, value) in storage.contents {
114+
let inherited = value.inheritedByAddedText && !value.isInvalidatedOnTextChange
115+
if inherited != inheritedByAddedText {
116+
storage[key] = nil
117+
}
118+
}
119+
return AttributeContainer(storage)
120+
}
121+
122+
/// Returns an attribute container storing only the attributes in `self` with a matching run boundary property
123+
///
124+
/// Note: if `nil` is provided then only attributes not bound to any particular boundary will be returned
125+
public func filter(runBoundaries: AttributedString.AttributeRunBoundaries?) -> AttributeContainer {
126+
var storage = self.storage
127+
for (key, value) in storage.contents {
128+
if value.runBoundaries != runBoundaries {
129+
storage[key] = nil
130+
}
131+
}
132+
return AttributeContainer(storage)
133+
}
134+
}

Tests/FoundationEssentialsTests/AttributedString/AttributedStringTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2578,4 +2578,25 @@ E {
25782578
}
25792579
}
25802580
}
2581+
2582+
func testAttributeContainerFiltering() {
2583+
XCTAssertEqual(AttributeContainer().filter(runBoundaries: nil), AttributeContainer())
2584+
XCTAssertEqual(AttributeContainer().filter(runBoundaries: .paragraph), AttributeContainer())
2585+
XCTAssertEqual(AttributeContainer().filter(inheritedByAddedText: true), AttributeContainer())
2586+
XCTAssertEqual(AttributeContainer().filter(inheritedByAddedText: false), AttributeContainer())
2587+
2588+
let testContainer = AttributeContainer.testInt(2).testBool(true).testString("Hello")
2589+
XCTAssertEqual(testContainer.filter(runBoundaries: nil), testContainer)
2590+
XCTAssertEqual(testContainer.filter(runBoundaries: .paragraph), AttributeContainer())
2591+
XCTAssertEqual(testContainer.filter(inheritedByAddedText: true), testContainer)
2592+
XCTAssertEqual(testContainer.filter(inheritedByAddedText: false), AttributeContainer())
2593+
2594+
let testConstrainedContainer = AttributeContainer.testInt(2).testParagraphConstrained(3).testCharacterConstrained(4).testNonExtended(5)
2595+
XCTAssertEqual(testConstrainedContainer.filter(runBoundaries: nil), AttributeContainer.testInt(2).testNonExtended(5))
2596+
XCTAssertEqual(testConstrainedContainer.filter(runBoundaries: .paragraph), AttributeContainer.testParagraphConstrained(3))
2597+
XCTAssertEqual(testConstrainedContainer.filter(runBoundaries: .character("A")), AttributeContainer())
2598+
XCTAssertEqual(testConstrainedContainer.filter(runBoundaries: .character("*")), AttributeContainer.testCharacterConstrained(4))
2599+
XCTAssertEqual(testConstrainedContainer.filter(inheritedByAddedText: true), AttributeContainer.testInt(2).testParagraphConstrained(3).testCharacterConstrained(4))
2600+
XCTAssertEqual(testConstrainedContainer.filter(inheritedByAddedText: false), AttributeContainer.testNonExtended(5))
2601+
}
25812602
}

0 commit comments

Comments
 (0)