harper_core/patterns/
word.rs1use super::SingleTokenPattern;
2
3use crate::{CharString, Token};
4
5#[derive(Clone)]
7pub struct Word {
8 word: CharString,
10 case_sensitive: bool,
12}
13
14impl Word {
15 pub fn new(word: &'static str) -> Self {
17 Self {
18 word: word.chars().collect(),
19 case_sensitive: false,
20 }
21 }
22
23 pub fn from_chars(word: &[char]) -> Self {
25 Self {
26 word: word.iter().copied().collect(),
27 case_sensitive: false,
28 }
29 }
30
31 pub fn from_char_string(word: CharString) -> Self {
33 Self {
34 word,
35 case_sensitive: false,
36 }
37 }
38
39 pub fn new_exact(word: &'static str) -> Self {
41 Self {
42 word: word.chars().collect(),
43 case_sensitive: true,
44 }
45 }
46}
47
48impl SingleTokenPattern for Word {
49 fn matches_token(&self, token: &Token, source: &[char]) -> bool {
50 if !token.kind.is_word() {
51 return false;
52 }
53 if token.span.len() != self.word.len() {
54 return false;
55 }
56
57 let chars = token.span.get_content(source);
58 if self.case_sensitive {
59 chars == self.word.as_slice()
60 } else {
61 chars
62 .iter()
63 .zip(&self.word)
64 .all(|(a, b)| a.eq_ignore_ascii_case(b))
65 }
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use crate::{Document, Span, patterns::DocPattern};
72
73 use super::Word;
74
75 #[test]
76 fn fruit() {
77 let doc = Document::new_markdown_default_curated("I ate a banana and an apple today.");
78
79 assert_eq!(
80 Word::new("banana").find_all_matches_in_doc(&doc),
81 vec![Span::new(6, 7)]
82 );
83 assert_eq!(
84 Word::new_exact("banana").find_all_matches_in_doc(&doc),
85 vec![Span::new(6, 7)]
86 );
87 }
88
89 #[test]
90 fn fruit_whack_capitalization() {
91 let doc = Document::new_markdown_default_curated("I Ate A bAnaNa And aN apPlE today.");
92
93 assert_eq!(
94 Word::new("banana").find_all_matches_in_doc(&doc),
95 vec![Span::new(6, 7)]
96 );
97 assert_eq!(
98 Word::new_exact("banana").find_all_matches_in_doc(&doc),
99 vec![]
100 );
101 }
102}