-
Notifications
You must be signed in to change notification settings - Fork 84
/
Copy pathmentions.rs
87 lines (81 loc) · 2.6 KB
/
mentions.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/// This provides a list of usernames or teams that were pinged in the text
/// provided.
///
/// It will appropriately skip mentions just like GitHub, i.e., mentions inside
/// code blocks will be ignored.
///
/// Note that the `@` is skipped in the final output.
pub fn get_mentions(input: &str) -> Vec<&str> {
let ignore_regions = crate::ignore_block::IgnoreBlocks::new(input);
let mut mentions = Vec::new();
for (idx, _) in input.match_indices('@') {
if let Some(previous) = input[..idx].chars().next_back() {
// A github username must stand apart from other text.
//
// Oddly enough, english letters do not work, but letters outside
// ASCII do work as separators; for now just go with this limited
// list.
if let 'a'..='z' | 'A'..='Z' | '0'..='9' = previous {
continue;
}
}
let mut saw_slash = false;
let username_end = input
.get(idx + 1..)
.unwrap_or_default()
.char_indices()
.find(|(_, terminator)| match terminator {
// These are the valid characters inside of a GitHub
// username
'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' => false,
'/' if !saw_slash => {
saw_slash = true;
false
}
_ => true,
})
.map(|(end, _)| idx + 1 + end)
.unwrap_or(input.len());
let username = input.get(idx + 1..username_end).unwrap_or_default();
if username.is_empty() {
continue;
}
if ignore_regions
.overlaps_ignore(idx..idx + username.len())
.is_some()
{
continue;
}
mentions.push(username);
}
mentions
}
#[test]
fn mentions_in_code_ignored() {
assert_eq!(
get_mentions("@rust-lang/libs `@user`"),
vec!["rust-lang/libs"]
);
assert_eq!(get_mentions("@user `@user`"), vec!["user"]);
assert_eq!(get_mentions("`@user`"), Vec::<&str>::new());
}
#[test]
fn italics() {
assert_eq!(get_mentions("*@rust-lang/libs*"), vec!["rust-lang/libs"]);
}
#[test]
fn slash() {
assert_eq!(
get_mentions("@rust-lang/libs/@rust-lang/release"),
vec!["rust-lang/libs", "rust-lang/release"]
);
}
#[test]
fn no_panic_lone() {
assert_eq!(get_mentions("@ `@`"), Vec::<&str>::new());
}
#[test]
fn no_email() {
assert_eq!(get_mentions("[email protected]"), Vec::<&str>::new());
assert_eq!(get_mentions("[email protected]"), Vec::<&str>::new());
}