diff --git a/Proton/Sources/Swift/Helpers/NSAttributedString+Range.swift b/Proton/Sources/Swift/Helpers/NSAttributedString+Range.swift index 578328bc..3fccfc29 100644 --- a/Proton/Sources/Swift/Helpers/NSAttributedString+Range.swift +++ b/Proton/Sources/Swift/Helpers/NSAttributedString+Range.swift @@ -140,4 +140,31 @@ public extension NSAttributedString { } return (string as NSString).substring(with: range) } + + /// Searches for given text in string + /// - Parameters: + /// - searchText: Text to search + /// - startingLocation: Starting location from which the text should be searched backwards + /// - isCaseInsensitive: Case insensitive search. Defaults to `true` + /// - Returns: Range of search text, if found. + func reverseRange(of searchText: String, startingLocation: Int, isCaseInsensitive: Bool = true) -> NSRange? { + guard startingLocation <= string.utf16.count else { + return nil + } + + let string = self.string as NSString + let cursorRange = NSRange(location: 0, length: startingLocation) + let text = string.substring(with: cursorRange) as NSString + var options: NSString.CompareOptions = [.backwards, .caseInsensitive] + if isCaseInsensitive == false { + options = [.backwards] + } + let searchTextRange = text.range(of: searchText, options: options) + guard searchTextRange.location != NSNotFound else { + return nil + } + + let range = NSRange(location: searchTextRange.location, length: searchText.count) + return range + } } diff --git a/Proton/Tests/ExtensionTests/NSAttributedStringExtensionTests.swift b/Proton/Tests/ExtensionTests/NSAttributedStringExtensionTests.swift index 3b45a86e..2c8a2ddc 100644 --- a/Proton/Tests/ExtensionTests/NSAttributedStringExtensionTests.swift +++ b/Proton/Tests/ExtensionTests/NSAttributedStringExtensionTests.swift @@ -164,4 +164,28 @@ class NSAttributedStringExtensionTests: XCTestCase { let range = attributedString.rangeOf(attribute: testAttribute, at: 0) XCTAssertNil(range) } + + func testGetsReverseRangeOfText() { + let text = NSMutableAttributedString(string: "This is a test string") + let range = text.reverseRange(of: "is", startingLocation: text.length - 1) + XCTAssertEqual(range, NSRange(location: 5, length: 2)) + } + + func testFailsReverseRangeOfTextCaseSensitive() { + let text = NSMutableAttributedString(string: "This is a test string") + let range = text.reverseRange(of: "Is", startingLocation: text.length - 1, isCaseInsensitive: false) + XCTAssertNil(range) + } + + func testGetsReverseRangeOfTextCaseSensitive() { + let text = NSMutableAttributedString(string: "This is a test string") + let range = text.reverseRange(of: "Is", startingLocation: text.length - 1) + XCTAssertEqual(range, NSRange(location: 5, length: 2)) + } + + func testDoesNotFindReverseRangeOfText() { + let text = NSMutableAttributedString(string: "This is a test string") + let range = text.reverseRange(of: "isx", startingLocation: text.length - 1) + XCTAssertNil(range) + } }