@@ -31,22 +31,26 @@ public final class TextAttachmentManager {
3131 layoutManager? . setNeedsLayout ( )
3232 }
3333
34- public func remove( atOffset offset: Int ) {
34+ /// Removes an attachment and invalidates layout for the removed range.
35+ /// - Parameter offset: The offset the attachment begins at.
36+ /// - Returns: The removed attachment, if it exists.
37+ @discardableResult
38+ public func remove( atOffset offset: Int ) -> AnyTextAttachment ? {
3539 let index = findInsertionIndex ( for: offset)
3640
3741 guard index < orderedAttachments. count && orderedAttachments [ index] . range. location == offset else {
38- assertionFailure ( " No attachment found at offset \( offset) " )
39- return
42+ return nil
4043 }
4144
4245 let attachment = orderedAttachments. remove ( at: index)
4346 layoutManager? . invalidateLayoutForRange ( attachment. range)
47+ return attachment
4448 }
4549
4650 /// Finds attachments starting in the given line range, and returns them as an array.
4751 /// Returned attachment's ranges will be relative to the _document_, not the line.
4852 /// - Complexity: `O(n log(n))`, ideally `O(log(n))`
49- public func get ( startingIn range: NSRange ) -> [ AnyTextAttachment ] {
53+ public func getAttachmentsStartingIn ( _ range: NSRange ) -> [ AnyTextAttachment ] {
5054 var results : [ AnyTextAttachment ] = [ ]
5155 var idx = findInsertionIndex ( for: range. location)
5256 while idx < orderedAttachments. count {
@@ -69,11 +73,11 @@ public final class TextAttachmentManager {
6973
7074 /// Returns all attachments whose ranges overlap the given query range.
7175 ///
72- /// - Parameter query : The `NSRange` to test for overlap.
76+ /// - Parameter range : The `NSRange` to test for overlap.
7377 /// - Returns: An array of `AnyTextAttachment` instances whose ranges intersect `query`.
74- public func get ( overlapping query : NSRange ) -> [ AnyTextAttachment ] {
78+ public func getAttachmentsOverlapping ( _ range : NSRange ) -> [ AnyTextAttachment ] {
7579 // Find the first attachment whose end is beyond the start of the query.
76- guard let startIdx = firstIndex ( where: { $0. range. upperBound > query . location } ) else {
80+ guard let startIdx = firstIndex ( where: { $0. range. upperBound > range . location } ) else {
7781 return [ ]
7882 }
7983
@@ -83,10 +87,10 @@ public final class TextAttachmentManager {
8387 // Collect every subsequent attachment that truly overlaps the query.
8488 while idx < orderedAttachments. count {
8589 let attachment = orderedAttachments [ idx]
86- if attachment. range. location >= query . upperBound {
90+ if attachment. range. location >= range . upperBound {
8791 break
8892 }
89- if NSIntersectionRange ( attachment. range, query ) . length > 0 ,
93+ if attachment. range. intersection ( range ) ? . length ?? 0 > 0 ,
9094 results. last? . range != attachment. range {
9195 results. append ( attachment)
9296 }
@@ -96,6 +100,11 @@ public final class TextAttachmentManager {
96100 return results
97101 }
98102
103+ /// Updates the text attachments to stay in the same relative spot after the edit, and removes any attachments that
104+ /// were in the updated range.
105+ /// - Parameters:
106+ /// - atOffset: The offset text was updated at.
107+ /// - delta: The change delta, positive is an insertion.
99108 package func textUpdated( atOffset: Int , delta: Int ) {
100109 for (idx, attachment) in orderedAttachments. enumerated ( ) . reversed ( ) {
101110 if attachment. range. contains ( atOffset) {
0 commit comments