From 71b33fcd0be45aeeb3bcfbe32816e2c1b078433f Mon Sep 17 00:00:00 2001 From: kernelkind Date: Sat, 20 Jan 2024 10:44:13 -0500 Subject: [PATCH] mention: allow mentioning users with punctuation characters in their names Finds the range of characters which represents a mention the user is typing in PostView. Previously the tokenizer used the standard granularity UITextGranularity.word, but this is insufficient for our use case for detecting when a mention ends. The criteria is simple: a mention starts with the '@' character and ends when there is a space, line break, or @, instead of when there is a new word. Closes: https://github.com/damus-io/damus/issues/1721 Changelog-Fixed: Allow mentioning users with punctuation characters in their names Lightning-url: LNURL1DP68GURN8GHJ7EM9W3SKCCNE9E3K7MF0D3H82UNVWQHKWUN9V4HXGCTHDC6RZVGR8SW3G Signed-off-by: kernelkind Reviewed-by: William Casarin Signed-off-by: William Casarin --- damus/Views/TextViewWrapper.swift | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/damus/Views/TextViewWrapper.swift b/damus/Views/TextViewWrapper.swift index f988974d..4a305bc4 100644 --- a/damus/Views/TextViewWrapper.swift +++ b/damus/Views/TextViewWrapper.swift @@ -119,7 +119,7 @@ struct TextViewWrapper: UIViewRepresentable { guard let selectedRange = textView.selectedTextRange else { return } - let wordRange = textView.tokenizer.rangeEnclosingPosition(selectedRange.start, with: .word, inDirection: .init(rawValue: UITextLayoutDirection.left.rawValue)) + let wordRange = rangeOfMention(in: textView, from: selectedRange.start) if let wordRange, let startPosition = textView.position(from: wordRange.start, offset: -1), @@ -131,6 +131,27 @@ struct TextViewWrapper: UIViewRepresentable { getFocusWordForMention?(val.0, val.1) } + + func rangeOfMention(in textView: UITextView, from position: UITextPosition) -> UITextRange? { + var startPosition = position + + while startPosition != textView.beginningOfDocument { + guard let previousPosition = textView.position(from: startPosition, offset: -1), + let range = textView.textRange(from: previousPosition, to: startPosition), + let text = textView.text(in: range), !text.isEmpty, + let lastChar = text.last else { + break + } + + if [" ", "\n", "@"].contains(lastChar) { + break + } + + startPosition = previousPosition + } + + return startPosition == position ? nil : textView.textRange(from: startPosition, to: position) + } private func convertToNSRange( _ startPosition: UITextPosition, _ endPosition: UITextPosition, _ textView: UITextView) -> NSRange? { let startOffset = textView.offset(from: textView.beginningOfDocument, to: startPosition)