diff --git a/bitchat/Services/MessageFormattingEngine.swift b/bitchat/Services/MessageFormattingEngine.swift index 88a32e3c..419e9e02 100644 --- a/bitchat/Services/MessageFormattingEngine.swift +++ b/bitchat/Services/MessageFormattingEngine.swift @@ -41,7 +41,9 @@ final class MessageFormattingEngine { enum Patterns { static let hashtag = SafeRegex.compile("#([a-zA-Z0-9_]+)") - static let mention = SafeRegex.compile("@([\\p{L}0-9_]+(?:#[a-fA-F0-9]{4})?)") + // Include \p{M} so NFD nicknames (base letter + combining mark) still + // parse as one mention token; NFC forms are covered by \p{L} alone. + static let mention = SafeRegex.compile("@([\\p{L}\\p{M}0-9_]+(?:#[a-fA-F0-9]{4})?)") static let cashu = SafeRegex.compile("\\bcashu[AB][A-Za-z0-9._-]{40,}\\b") diff --git a/bitchat/ViewModels/ChatComposerCoordinator.swift b/bitchat/ViewModels/ChatComposerCoordinator.swift index 9eb8128b..0e52b3f3 100644 --- a/bitchat/ViewModels/ChatComposerCoordinator.swift +++ b/bitchat/ViewModels/ChatComposerCoordinator.swift @@ -116,6 +116,9 @@ final class ChatComposerCoordinator { } func parseMentions(from content: String) -> [String] { + // Canonicalize before matching so NFD typed text and NFC peer tokens + // share one codepoint sequence (regex also accepts combining marks). + let content = content.precomposedStringWithCanonicalMapping let regex = ChatViewModel.Patterns.mention let nsContent = content as NSString let matches = regex.matches(