Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ extension AttributeContainer {

@available(FoundationPreview 6.2, *)
extension AttributeContainer {
/// Returns an attribute container storing only the attributes in `self` with the `inheritedByAddedText` property set to `true`
/// Returns a copy of the attribute container with only attributes that specify the provided inheritance behavior.
/// - Parameter inheritedByAddedText: An `inheritedByAddedText` value to filter. Attributes matching this value are included in the returned container.
/// - Returns: A copy of the attribute container with only attributes whose `inheritedByAddedText` property matches the provided value.
public func filter(inheritedByAddedText: Bool) -> AttributeContainer {
var storage = self.storage
for (key, value) in storage.contents {
Expand All @@ -120,9 +122,9 @@ extension AttributeContainer {
return AttributeContainer(storage)
}

/// Returns an attribute container storing only the attributes in `self` with a matching run boundary property
///
/// Note: if `nil` is provided then only attributes not bound to any particular boundary will be returned
/// Returns a copy of the attribute container with only attributes that have the provided run boundaries.
/// - Parameter runBoundaries: The required `runBoundaries` value of the filtered attributes. If `nil` is provided, only attributes not bound to any specific boundary will be returned.
/// - Returns: A copy of the attribute container with only attributes whose `runBoundaries` property matches the provided value.
public func filter(runBoundaries: AttributedString.AttributeRunBoundaries?) -> AttributeContainer {
var storage = self.storage
for (key, value) in storage.contents {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ extension AttributeScope {
Self.scopeDescription.markdownAttributes
}

/// A list of all attribute keys contained within this scope and any sub-scopes.
@available(FoundationPreview 6.2, *)
public static var attributeKeys: some Sequence<any AttributedStringKey.Type> {
Self.scopeDescription.attributes.values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,25 @@ extension AttributedString.Guts {
extension AttributedString {
// MARK: inout API

/// Tracks the location of the provided range throughout the mutation closure, updating the provided range to one that represents the same effective locations after the mutation. If updating the provided range is not possible (tracking failed) then this function will fatal error. Use the Optional-returning variants to provide custom fallback behavior.
/// Tracks the location of the provided range throughout the mutation closure, updating the provided range to one that represents the same effective locations after the mutation.
///
/// If updating the provided range is not possible (tracking failed) then this function will fatal error. Use the `Optional`-returning variants to provide custom fallback behavior.
/// - Parameters:
/// - range: a range to track throughout the `body` closure
/// - body: a mutating operation, or set of operations, to perform on the value of `self`. The value of `self` is provided to the closure as an `inout AttributedString` that the closure should mutate directly. Do not capture the value of `self` in the provided closure - the closure should mutate the provided `inout` copy.
/// - range: A range to track throughout the `body` closure.
/// - body: A mutating operation, or set of operations, to perform on the value of `self`. The value of `self` is provided to the closure as an `inout AttributedString` that the closure should mutate directly. Do not capture the value of `self` in the provided closure - the closure should mutate the provided `inout` copy.
public mutating func transform<E>(updating range: inout Range<Index>, body: (inout AttributedString) throws(E) -> Void) throws(E) -> Void {
guard let result = try self.transform(updating: range, body: body) else {
fatalError("The provided mutation body did not allow for maintaining index tracking. Ensure that your mutation body mutates the provided AttributedString instead of replacing it with a different AttributedString or use the non-inout version of transform(updating:body:) which returns an Optional value to provide fallback behavior.")
}
range = result
}

/// Tracks the location of the provided ranges throughout the mutation closure, updating them to new ranges that represent the same effective locations after the mutation. If updating the provided ranges is not possible (tracking failed) then this function will fatal error. Use the Optional-returning variants to provide custom fallback behavior.
/// Tracks the location of the provided ranges throughout the mutation closure, updating them to new ranges that represent the same effective locations after the mutation.
///
/// If updating the provided ranges is not possible (tracking failed) then this function will fatal error. Use the `Optional`-returning variants to provide custom fallback behavior.
/// - Parameters:
/// - ranges: a list of ranges to track throughout the `body` closure. The updated array (after the function is called) is guaranteed to be the same size as the provided array. Updated ranges are located at the same indices as their respective original ranges in the input `ranges` array.
/// - body: a mutating operation, or set of operations, to perform on the value of `self`. The value of `self` is provided to the closure as an `inout AttributedString` that the closure should mutate directly. Do not capture the value of `self` in the provided closure - the closure should mutate the provided `inout` copy.
/// - ranges: A list of ranges to track throughout the `body` closure. The updated array (after the function is called) is guaranteed to be the same size as the provided array. Updated ranges are located at the same indices as their respective original ranges in the input `ranges` array.
/// - body: A mutating operation, or set of operations, to perform on the value of `self`. The value of `self` is provided to the closure as an `inout AttributedString` that the closure should mutate directly. Do not capture the value of `self` in the provided closure - the closure should mutate the provided `inout` copy.
public mutating func transform<E>(updating ranges: inout [Range<Index>], body: (inout AttributedString) throws(E) -> Void) throws(E) -> Void {
guard let result = try self.transform(updating: ranges, body: body) else {
fatalError("The provided mutation body did not allow for maintaining index tracking. Ensure that your mutation body mutates the provided AttributedString instead of replacing it with a different AttributedString or use the non-inout version of transform(updating:body:) which returns an Optional value to provide fallback behavior.")
Expand All @@ -103,20 +107,20 @@ extension AttributedString {

// MARK: Optional-returning API

/// Tracks the location of the provided range throughout the mutation closure, returning a new, updated range that represents the same effective locations after the mutation
/// Tracks the location of the provided range throughout the mutation closure, returning a new, updated range that represents the same effective locations after the mutation.
/// - Parameters:
/// - range: a range to track throughout the `mutation` block
/// - mutation: a mutating operation, or set of operations, to perform on this `AttributedString`
/// - Returns: the updated `Range` that is valid after the mutation has been performed, or `nil` if the mutation performed does not allow for tracking to succeed (such as replacing the provided inout variable with an entirely different AttributedString)
/// - range: A range to track throughout the `body` block.
/// - body: A mutating operation, or set of operations, to perform on this `AttributedString`.
/// - Returns: the updated `Range` that is valid after the mutation has been performed, or `nil` if the mutation performed does not allow for tracking to succeed (such as replacing the provided inout variable with an entirely different `AttributedString`).
public mutating func transform<E>(updating range: Range<Index>, body: (inout AttributedString) throws(E) -> Void) throws(E) -> Range<Index>? {
try self.transform(updating: [range], body: body)?.first
}

/// Tracks the location of the provided ranges throughout the mutation closure, returning a new, updated range that represents the same effective locations after the mutation
/// - Parameters:
/// - index: an index to track throughout the `mutation` block
/// - mutation: a mutating operation, or set of operations, to perform on this `AttributedString`
/// - Returns: the updated `Range`s that is valid after the mutation has been performed, or `nil` if the mutation performed does not allow for tracking to succeed (such as replacing the provided inout variable with an entirely different AttributedString). When the return value is non-nil, the returned array is guaranteed to be the same size as the provided array with updated ranges at the same Array indices as their respective original ranges in the input array.
/// - ranges: Ranges to track throughout the `body` block.
/// - body: A mutating operation, or set of operations, to perform on this `AttributedString`.
/// - Returns: the updated `Range`s that are valid after the mutation has been performed or `nil` if the mutation performed does not allow for tracking to succeed (such as replacing the provided inout variable with an entirely different `AttributedString`). When the return value is non-`nil`, the returned array is guaranteed to be the same size as the provided array with updated ranges at the same indices as their respective original ranges in the input array.
public mutating func transform<E>(updating ranges: [Range<Index>], body: (inout AttributedString) throws(E) -> Void) throws(E) -> [Range<Index>]? {
precondition(!ranges.isEmpty, "Cannot update an empty array of ranges")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,18 @@ extension AttributedString.Guts {

@available(FoundationPreview 6.2, *)
extension AttributedString.Index {
/// Indicates whether the index is valid for use with the provided attributed string.
/// - Parameter text: An attributed string used to validate the index.
/// - Returns: `true` when the index is valid for use with the provided attributed string; otherwise, false. An index is valid if it is both within the bounds of the attributed string and was produced from the provided string without any intermediate mutations.
public func isValid(within text: some AttributedStringProtocol) -> Bool {
self._version == text.__guts.version &&
self >= text.startIndex &&
self < text.endIndex
}

/// Indicates whether the index is valid for use with the provided discontiguous attributed string.
/// - Parameter text: A discontiguous attributed string used to validate the index.
/// - Returns: `true` when the index is valid for use with the provided discontiguous attributed string; otherwise, false. An index is valid if it is both within the bounds of the discontigous attributed string and was produced from the provided string without any intermediate mutations.
public func isValid(within text: DiscontiguousAttributedSubstring) -> Bool {
self._version == text._guts.version &&
text._indices.contains(self._value)
Expand All @@ -59,6 +65,9 @@ extension AttributedString.Index {

@available(FoundationPreview 6.2, *)
extension Range<AttributedString.Index> {
/// Indicates whether the range is valid for use with the provided attributed string.
/// - Parameter text: An attributed string used to validate the range.
/// - Returns: `true` when the range is valid for use with the provided attributed string; otherwise, false. A range is valid if its lower and upper bounds are each either valid in the attributed string or equivalent to the string's `endIndex`.
public func isValid(within text: some AttributedStringProtocol) -> Bool {
// Note: By nature of Range's lowerBound <= upperBound requirement, this is also sufficient to determine that lowerBound <= endIndex && upperBound >= startIndex
self.lowerBound._version == text.__guts.version &&
Expand All @@ -67,6 +76,9 @@ extension Range<AttributedString.Index> {
self.upperBound <= text.endIndex
}

/// Indicates whether the range is valid for use with the provided discontiguous attributed string.
/// - Parameter text: A discontiguous attributed string used to validate the range.
/// - Returns: `true` when the range is valid for use with the provided discontiguous attributed string; otherwise, false. A range is valid if its lower and upper bounds are each either valid in the discontiguous attributed string or equivalent to the string's `endIndex`.
public func isValid(within text: DiscontiguousAttributedSubstring) -> Bool {
let endIndex = text._indices.ranges.last?.upperBound
return self.lowerBound._version == text._guts.version &&
Expand All @@ -78,12 +90,18 @@ extension Range<AttributedString.Index> {

@available(FoundationPreview 6.2, *)
extension RangeSet<AttributedString.Index> {
/// Indicates whether the range set is valid for use with the provided attributed string.
/// - Parameter text: An attributed string used to validate the range set.
/// - Returns: `true` when the range set is valid for use with the provided attributed string; otherwise, false. A range set is valid if each of its ranges are valid in the attributed string.
public func isValid(within text: some AttributedStringProtocol) -> Bool {
self.ranges.allSatisfy {
$0.isValid(within: text)
}
}

/// Indicates whether the range set is valid for use with the provided discontiguous attributed string.
/// - Parameter text: A discontigious attributed string used to validate the range set.
/// - Returns: `true` when the range set is valid for use with the provided discontiguous attributed string; otherwise, false. A range set is valid if each of its ranges are valid in the discontiguous attributed string.
public func isValid(within text: DiscontiguousAttributedSubstring) -> Bool {
self.ranges.allSatisfy {
$0.isValid(within: text)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal import _FoundationCollections

@available(FoundationPreview 6.2, *)
extension AttributedString {
/// A view of an attributed string’s contents as a collection of UTF-16 code units.
public struct UTF16View: Sendable {
internal var _guts: Guts
internal var _range: Range<BigString.Index>
Expand All @@ -35,13 +36,15 @@ extension AttributedString {
}
}

/// A view of the attributed string’s contents as a collection of UTF-16 code units.
public var utf16: UTF16View {
UTF16View(_guts)
}
}

@available(FoundationPreview 6.2, *)
extension AttributedSubstring {
/// A view of the attributed substring's contents as a collection of UTF-16 code units.
public var utf16: AttributedString.UTF16View {
AttributedString.UTF16View(_guts, in: _range)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal import _FoundationCollections

@available(FoundationPreview 6.2, *)
extension AttributedString {
/// A view of an attributed string’s contents as a collection of UTF-8 code units.
public struct UTF8View: Sendable {
internal var _guts: Guts
internal var _range: Range<BigString.Index>
Expand All @@ -34,14 +35,16 @@ extension AttributedString {
_range = range
}
}


/// A view of the attributed string’s contents as a collection of UTF-8 code units.
public var utf8: UTF8View {
UTF8View(_guts)
}
}

@available(FoundationPreview 6.2, *)
extension AttributedSubstring {
/// A view of the attributed substring's contents as a collection of UTF-8 code units.
public var utf8: AttributedString.UTF8View {
AttributedString.UTF8View(_guts, in: _range)
}
Expand Down
Loading