Hi everyone! In addition to other recent AttributedString
APIs that I've pitched, I'd also like to pitch new APIs for AttributedString
to support operations over discontiguous subranges. These APIs mirror those introduced by SE-0270 on Collection
itself, and I'd love to hear any thoughts/feedback on introducing similar APIs to better support those operations on AttributedString
s. Check out the details below:
AttributedString Discontiguous Operations
- Proposal: SF-NNNN
- Authors: Jeremy Schonfeld
- Review Manager: TBD
- Status: Pitch
Introduction
In SE-0270, we added a new RangeSet
type to Swift (representing a sorted, noncontiguous set of ranges in a collection) along with collection APIs that perform operations over referenced noncontiguous elements. These APIs have proved beneficial for use in a variety of collections to easily locate, identify, and mutate multiple ranges of elements in single expressions. AttributedString
has already benefitted from these generic collection APIs that are available via the character, unicode scalar, and runs view. However, as AttributedString
does not conform to Collection
itself, it lacks proper, fully integrated support for operations over discontiguous segments.
Motivation
Using RangeSet
-based APIs provided on the AttributedString
type directly instead of its individual collection views can be very beneficial. In particular, full support for discontiguous representations of an AttributedString
are critical for modeling concepts such as an AttributedString
's selection from a UI (either multiple, discontiguous visual collections or a singular visual selection that maps to discontiguous ranges in the logical text storage due to mixed RTL/LTR text). Discontiguous operations would allow for not only iterating over discontiguous contents but will also add the ability to mutate attributes over these discontiguous ranges (which is not possible today with the immutable runs
view). We feel that providing these tools will improve the parity between AttributedString
and other standard collection types (like String
) and will set up AttributedString
for success as the best model representation of rich text.
Proposed solution
Developers can use APIs provided by the standard library today to create RangeSet
s representing indices:
var text = AttributedString("Hello, world!")
let indicesOfL: RangeSet<AttributedString.Index> = text.characters.indices(of: "l")
These new APIs will allow developers to use those indices on AttributedString
operations, such as the following:
// Make all "l"s blue
text[indicesOfL].foregroundColor = .blue
print(text[indicesOfL]) // "lll { SwiftUI.ForegroundColor = ... }"
// Iterate all foreground colors on the "l"s
for (range, color) in text[indicesOfL].runs[\.foregroundColor] {
// ...
}
For the full detailed design along with alternatives considered and future directions, check out the full proposal on the swift-foundation repo PR.