UITextView+Extensions.swift 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. //
  2. // UITextView+Extensions.swift
  3. // InputBarAccessoryView
  4. //
  5. // Created by Nathan Tannar on 09/18/18.
  6. // Copyright © 2018 Nathan Tannar. All rights reserved.
  7. //
  8. import UIKit
  9. internal extension UITextView {
  10. typealias Match = (prefix: String, word: String, range: NSRange)
  11. func find(prefixes: Set<String>, with delimiterSet: CharacterSet) -> Match? {
  12. guard prefixes.count > 0 else { return nil }
  13. for prefix in prefixes {
  14. if let match = find(prefix: prefix, with: delimiterSet) {
  15. return match
  16. }
  17. }
  18. return nil
  19. }
  20. func find(prefix: String, with delimiterSet: CharacterSet) -> Match? {
  21. guard !prefix.isEmpty else { return nil }
  22. guard let caretRange = self.caretRange else { return nil }
  23. guard let cursorRange = Range(caretRange, in: text) else { return nil }
  24. let leadingText = text[..<cursorRange.upperBound]
  25. var prefixStartIndex: String.Index!
  26. for (i, char) in prefix.enumerated() {
  27. guard let index = leadingText.lastIndex(of: char) else { return nil }
  28. if i == 0 {
  29. prefixStartIndex = index
  30. } else if index.utf16Offset(in: leadingText) == prefixStartIndex.utf16Offset(in: leadingText) + 1 {
  31. prefixStartIndex = index
  32. } else {
  33. return nil
  34. }
  35. }
  36. let wordRange = prefixStartIndex..<cursorRange.upperBound
  37. let word = leadingText[wordRange]
  38. let location = wordRange.lowerBound.utf16Offset(in: leadingText)
  39. let length = wordRange.upperBound.utf16Offset(in: word) - location
  40. let range = NSRange(location: location, length: length)
  41. return (String(prefix), String(word), range)
  42. }
  43. var caretRange: NSRange? {
  44. guard let selectedRange = self.selectedTextRange else { return nil }
  45. return NSRange(
  46. location: offset(from: beginningOfDocument, to: selectedRange.start),
  47. length: offset(from: selectedRange.start, to: selectedRange.end)
  48. )
  49. }
  50. }