Fix detecting mentions while typing

This commit is contained in:
Shadowfacts 2024-09-13 10:52:49 -04:00
parent cad074bcc3
commit 7d47f1f259
1 changed files with 12 additions and 2 deletions

View File

@ -101,6 +101,9 @@ private struct NewMainTextViewRepresentable: UIViewRepresentable {
} }
} }
// laxer than the CharacterCounter regex, because we want to find mentions that are being typed but aren't yet complete (e.g., "@a@b")
private let mentionRegex = try! NSRegularExpression(pattern: "(@[a-z0-9_]+)(?:@[a-z0-9\\-\\.]+)?", options: .caseInsensitive)
private final class WrappedTextViewCoordinator: NSObject { private final class WrappedTextViewCoordinator: NSObject {
private static let attachment: NSTextAttachment = { private static let attachment: NSTextAttachment = {
let font = UIFont.systemFont(ofSize: 20) let font = UIFont.systemFont(ofSize: 20)
@ -149,6 +152,7 @@ private final class WrappedTextViewCoordinator: NSObject {
private func updateAttributes(in textView: UITextView) { private func updateAttributes(in textView: UITextView) {
let str = NSMutableAttributedString(attributedString: textView.attributedText!) let str = NSMutableAttributedString(attributedString: textView.attributedText!)
var changed = false var changed = false
var cursorOffset = 0
// remove existing mentions that aren't valid // remove existing mentions that aren't valid
str.enumerateAttribute(.mention, in: NSRange(location: 0, length: str.length), options: .reverse) { value, range, stop in str.enumerateAttribute(.mention, in: NSRange(location: 0, length: str.length), options: .reverse) { value, range, stop in
@ -157,18 +161,19 @@ private final class WrappedTextViewCoordinator: NSObject {
if hasTextAttachment { if hasTextAttachment {
substr = String(substr.dropFirst()) substr = String(substr.dropFirst())
} }
if CharacterCounter.mention.numberOfMatches(in: substr, range: NSRange(location: 0, length: substr.utf16.count)) == 0 { if mentionRegex.numberOfMatches(in: substr, range: NSRange(location: 0, length: substr.utf16.count)) == 0 {
changed = true changed = true
str.removeAttribute(.mention, range: range) str.removeAttribute(.mention, range: range)
str.removeAttribute(.foregroundColor, range: range) str.removeAttribute(.foregroundColor, range: range)
if hasTextAttachment { if hasTextAttachment {
str.deleteCharacters(in: NSRange(location: range.location, length: 1)) str.deleteCharacters(in: NSRange(location: range.location, length: 1))
cursorOffset -= 1
} }
} }
} }
// add mentions for those missing // add mentions for those missing
let mentionMatches = CharacterCounter.mention.matches(in: str.string, range: NSRange(location: 0, length: str.length)) let mentionMatches = mentionRegex.matches(in: str.string, range: NSRange(location: 0, length: str.length))
for match in mentionMatches.reversed() { for match in mentionMatches.reversed() {
var attributeRange = NSRange() var attributeRange = NSRange()
let attribute = str.attribute(.mention, at: match.range.location, effectiveRange: &attributeRange) let attribute = str.attribute(.mention, at: match.range.location, effectiveRange: &attributeRange)
@ -179,6 +184,7 @@ private final class WrappedTextViewCoordinator: NSObject {
if attribute == nil { if attribute == nil {
str.insert(NSAttributedString(attachment: Self.attachment), at: match.range.location) str.insert(NSAttributedString(attachment: Self.attachment), at: match.range.location)
newAttributeRange = NSRange(location: match.range.location, length: match.range.length + 1) newAttributeRange = NSRange(location: match.range.location, length: match.range.length + 1)
cursorOffset += 1
} else { } else {
newAttributeRange = match.range newAttributeRange = match.range
} }
@ -190,7 +196,11 @@ private final class WrappedTextViewCoordinator: NSObject {
} }
if changed { if changed {
let selection = textView.selectedRange
textView.attributedText = str textView.attributedText = str
textView.selectedRange = NSRange(location: selection.location + cursorOffset, length: selection.length)
} }
} }
} }