fix: strip emoji between bot mention and command text

strip_mention_separator now skips all non-ASCII-alphanumeric chars
(emoji, colons, spaces) and returns a slice starting at the first
command character. Fixes mention pills with emoji display names
(e.g. "timmy ️ status") not matching bot commands.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dave
2026-04-02 18:06:52 +00:00
parent 7ff88641c0
commit d37fdf8e10
+20 -8
View File
@@ -72,16 +72,19 @@ pub fn strip_bot_mention<'a>(message: &'a str, bot_name: &str, bot_user_id: &str
trimmed
}
/// Strip an optional Element tab-completion separator (`:` or `,`) and
/// surrounding whitespace from the start of text that follows a bot mention.
/// Strip decoration between a bot mention and the command text.
///
/// Element's tab-completion inserts `DisplayName: ` (colon + space) after the
/// name. Without this strip the leading `:` would be treated as part of the
/// command name and no command would match.
/// After the bot name/ID is stripped, what remains may include whitespace,
/// emoji from display names (e.g. `Timmy ⚡️`), and Element tab-completion
/// separators (`:` or `,`). This function skips all of that and returns a
/// slice starting at the first ASCII alphanumeric character (the command).
fn strip_mention_separator(rest: &str) -> &str {
let rest = rest.trim_start();
let rest = rest.strip_prefix([',', ':']).unwrap_or(rest);
rest.trim_start()
let byte_skip = rest
.char_indices()
.find(|(_, c)| c.is_ascii_alphanumeric())
.map(|(i, _)| i)
.unwrap_or(rest.len());
&rest[byte_skip..]
}
/// Returns `true` when `text` ends while inside an open fenced code block.
@@ -381,6 +384,15 @@ mod tests {
assert_eq!(rest, "help");
}
#[test]
fn strip_mention_short_name_emoji_suffix_in_body() {
// bot_name is "Timmy" (no emoji) but Element mention pill puts
// "Timmy ⚡️ status" in the body — the emoji is part of the display
// name as set on the Matrix server, not in bot.toml.
let rest = strip_bot_mention("Timmy ⚡️ status", "Timmy", "@timmy:homeserver.local");
assert_eq!(rest, "status");
}
// -- drain_complete_paragraphs ------------------------------------------
#[test]