diff --git a/src/nick.rs b/src/nick.rs index a6cadc2..4a11393 100644 --- a/src/nick.rs +++ b/src/nick.rs @@ -53,13 +53,6 @@ pub fn hue(emoji: &Emoji, nick: &str) -> u8 { hue_without_removing_emoji(&emoji.remove(nick)) } -fn delimits_mention(c: char) -> bool { - match c { - ',' | '.' | '!' | '?' | ';' | '&' | '<' | '>' | '\'' | '"' => true, - _ => c.is_whitespace(), - } -} - /// Normalize a nick to a form that can be compared against other nicks. /// /// This normalization is less aggressive than the nick hue normalization. It is @@ -73,11 +66,7 @@ fn delimits_mention(c: char) -> bool { /// /// The steps performed are as follows: /// -/// 1. Remove all whitespace characters as well as the characters -/// `,`, `.`, `!`, `?`, `;`, `&`, `<`, `>`, `'`, `"`. -/// All of these are used by the [frontend to delimit mentions][0]. -/// The `>` character was confirmed to delimit mentions via experimentation. -/// +/// 1. Apply [`mention`] /// 2. Convert to NFKC /// 3. Case fold /// @@ -87,13 +76,19 @@ fn delimits_mention(c: char) -> bool { /// /// [0]: https://github.com/euphoria-io/heim/blob/978c921063e6b06012fc8d16d9fbf1b3a0be1191/client/lib/stores/chat.js#L14 pub fn normalize(nick: &str) -> String { - nick.chars() - .filter(|c| !delimits_mention(*c)) // Step 1 + mention(nick) // Step 1 .nfkc() // Step 2 .default_case_fold() // Step 3 .collect() } +fn is_non_whitespace_delimiter(c: char) -> bool { + matches!( + c, + ',' | '.' | '!' | '?' | ';' | '&' | '<' | '>' | '\'' | '"' + ) +} + /// Compute a mentionable version of a nick while remaining as close to the /// original as possible. /// @@ -101,7 +96,20 @@ pub fn normalize(nick: &str) -> String { /// highlight as a mention in the official euphoria client. It should ping any /// people using the original nick. It might also ping other people. /// -/// This function performs step 1 of [`normalize`]. +/// In the official euphoria client, mentions are non-whitespace characters +/// delimited by whitespace and any of the following characters: +/// +/// `,`, `.`, `!`, `?`, `;`, `&`, `<`, `>`, `'`, `"`. +/// +/// The first character of a mention may be a delimiting character. pub fn mention(nick: &str) -> String { - nick.replace(delimits_mention, "") + let mut nick = nick.chars().filter(|c| !c.is_whitespace()); + let mut result = String::new(); + if let Some(c) = nick.next() { + result.push(c); + } + for c in nick.filter(|c| !is_non_whitespace_delimiter(*c)) { + result.push(c); + } + result }