extension UITextView {
func correctSelection() {
let currentSelectedRange = selectedRange
let wholeRange = attributedText.wholeRange
let emptyRange = NSRange()
var lowerAttributeEffectiveRange = NSRange()
var upperAttributeEffectiveRange = NSRange()
let validRange = NSRange(
location: wholeRange.lowerBound + 1,
length: wholeRange.length - 2
)
let lowerBindingText: String? = {
var text: String? = nil
if validRange.contains(currentSelectedRange.lowerBound) {
text = attributedText.attribute(
NSAttributedStringKey.bindingText,
at: currentSelectedRange.lowerBound,
longestEffectiveRange: &lowerAttributeEffectiveRange,
in: wholeRange
) as? String
}
return text
}()
if lowerBindingText == nil {
lowerAttributeEffectiveRange = emptyRange
}
let upperBindingText: String? = {
var text: String? = nil
if validRange.contains(currentSelectedRange.upperBound - 1) {
text = attributedText.attribute(
NSAttributedStringKey.bindingText,
at: currentSelectedRange.upperBound - 1,
longestEffectiveRange: &upperAttributeEffectiveRange,
in: wholeRange
) as? String
}
return text
}()
if upperBindingText == nil {
upperAttributeEffectiveRange = emptyRange
}
guard currentSelectedRange.upperBound != lowerAttributeEffectiveRange.lowerBound else { return }
switch (lowerAttributeEffectiveRange, upperAttributeEffectiveRange) {
case (emptyRange, emptyRange):
break
case (let effectiveRange, emptyRange), (emptyRange, let effectiveRange):
selectedRange = currentSelectedRange
.union(effectiveRange)
case (_, _):
selectedRange = currentSelectedRange
.union(lowerAttributeEffectiveRange)
.union(upperAttributeEffectiveRange)
}
}
}