Skip to content

Commit

Permalink
Improve matching when highligting mentions
Browse files Browse the repository at this point in the history
Simple substring search as we did before highlights messages when e.g.
the nick is "abc" and the message is "abcd".

We now take IRC nick syntax into account and only match when the nick
occurs between invalid IRC nick characters.

Fixes: #430
  • Loading branch information
osa1 committed Apr 6, 2024
1 parent 1637216 commit 6993ce5
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Unreleased

- Improve nick matching to avoid highlighting message incorrectly. (#430)

# 2024/01/01: 0.12.0

Thanks to @nate-sys and @jubalh for contributing to this release.
Expand Down
52 changes: 50 additions & 2 deletions crates/tiny/src/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ fn handle_irc_msg(ui: &UI, client: &dyn Client, msg: wire::Msg) {
match target {
wire::MsgTarget::Chan(chan) => {
let ui_msg_target = MsgTarget::Chan { serv, chan: &chan };
// highlight the message if it mentions us
if msg.contains(&client.get_nick()) {
// Highlight the message if it mentions us.
if mentions_user(&msg, &client.get_nick()) {
ui.add_privmsg(sender, &msg, ts, &ui_msg_target, true, is_action);
ui.set_tab_style(TabStyle::Highlight, &ui_msg_target);
let mentions_target = MsgTarget::Server { serv: "mentions" };
Expand Down Expand Up @@ -591,3 +591,51 @@ fn handle_irc_msg(ui: &UI, client: &dyn Client, msg: wire::Msg) {
},
}
}

/// Whether `msg` mentions `nick`.
///
/// This takes IRC nick syntax into account (following [1]) when checking match boundaries, to
/// avoid generating highlights incorrectly. For example, if the nick is "abc" and the messsage is
/// "abcd" we don't consider that a mention, but we consider it a mention in message "abc: hi".
///
/// [1]: https://modern.ircdocs.horse/#clients
fn mentions_user(msg: &str, nick: &str) -> bool {
for (match_idx, _) in msg.match_indices(nick) {
if check_nick_left_boundary(msg, match_idx)
&& check_nick_right_boundary(msg, match_idx + nick.len())
{
return true;
}
}

false
}

fn check_nick_left_boundary(msg: &str, idx: usize) -> bool {
if idx == 0 {
return true;
}

matches!(
msg.as_bytes()[idx - 1],
b' ' | b',' | b'*' | b'?' | b'!' | b'@' | b'.' | b'&' | b':' | b'#' | b'+' | b'~'
)
}

fn check_nick_right_boundary(msg: &str, idx: usize) -> bool {
matches!(
msg.as_bytes().get(idx),
None | Some(b' ' | b',' | b'*' | b'?' | b'!' | b'@' | b'.' | b':')
)
}

#[test]
fn mention_check() {
assert!(!mentions_user("", "abc"));
assert!(mentions_user("abc", "abc"));
assert!(mentions_user("abc: hi", "abc"));
assert!(mentions_user(" abc", "abc"));
assert!(mentions_user(" abc,", "abc"));
assert!(!mentions_user(" aaaa ", "aa"));
assert!(mentions_user(" aa,aa ", "aa"));
}

0 comments on commit 6993ce5

Please sign in to comment.