From 7d47f1f25930e63f593beaff9cba7d0b4de62f8f Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Fri, 13 Sep 2024 10:52:49 -0400 Subject: [PATCH] Fix detecting mentions while typing --- .../Sources/ComposeUI/Views/NewMainTextView.swift | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/NewMainTextView.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/NewMainTextView.swift index 49c998c8..d352026e 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/NewMainTextView.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/NewMainTextView.swift @@ -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 static let attachment: NSTextAttachment = { let font = UIFont.systemFont(ofSize: 20) @@ -149,6 +152,7 @@ private final class WrappedTextViewCoordinator: NSObject { private func updateAttributes(in textView: UITextView) { let str = NSMutableAttributedString(attributedString: textView.attributedText!) var changed = false + var cursorOffset = 0 // remove existing mentions that aren't valid 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 { 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 str.removeAttribute(.mention, range: range) str.removeAttribute(.foregroundColor, range: range) if hasTextAttachment { str.deleteCharacters(in: NSRange(location: range.location, length: 1)) + cursorOffset -= 1 } } } // 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() { var attributeRange = NSRange() let attribute = str.attribute(.mention, at: match.range.location, effectiveRange: &attributeRange) @@ -179,6 +184,7 @@ private final class WrappedTextViewCoordinator: NSObject { if attribute == nil { str.insert(NSAttributedString(attachment: Self.attachment), at: match.range.location) newAttributeRange = NSRange(location: match.range.location, length: match.range.length + 1) + cursorOffset += 1 } else { newAttributeRange = match.range } @@ -190,7 +196,11 @@ private final class WrappedTextViewCoordinator: NSObject { } if changed { + let selection = textView.selectedRange + textView.attributedText = str + + textView.selectedRange = NSRange(location: selection.location + cursorOffset, length: selection.length) } } }